Sei sulla pagina 1di 266

Brauliro Gonçalves Leal

Programação Básica com Linguagem C

Terceira Edição

Juazeiro – BA
2020
Programação Básica com Linguagem C 2

Copyright© 2012, 2018, 2019, 2020 by Brauliro Gonçalves Leal

O conteúdo deste livro eletrônico é totalmente livre para uso de qualquer natureza
desde que citado a fonte. Toda e qualquer parte desta publicação pode ser
reproduzida, distribuída ou transmitida de qualquer forma ou por qualquer meio, ou
armazenada de qualquer forma ou em qualquer sistema desde que reconhecida a
autoria.

Atribuição–CompartilhaIgual – esta licença permite que outros remixem,


adaptem e criem a partir deste trabalho, mesmo para fins comerciais,
desde que lhe atribuam o devido crédito e que licenciem as novas
criações sob termos idênticos (creativecommons.org/licenses).

Terceira Edição Eletrônica: Agosto de 2020


ISBN: a ser feito#

O autor

Brauliro Gonçalves Leal

Professor do Colegiado de Engenharia da Computação


Universidade Federal do Vale do São Francisco
Avenida Antônio Carlos Magalhães, 510 Santo Antônio
Juazeiro/BA – Brasil 48.902–300

e–mail: brauliro.leal@univasf.edu.br
site: www.univasf.edu.br/~brauliro.leal

Sobre este documento

Este documento foi escrito em LibreOffice (www.libreoffice.org), suas imagens


foram produzidas pelo Kolourpaint (www.kolourpaint.org), seus programas foram
editados na IDE Code::Blocks (www.codeblocks.org) e compilados com o GNU GCC
(gcc.gnu.org). O Sistema Operacional utilizado foi o GNU/Linux Mint Cinnamon.

Software livre é uma boa ideia.


Programação Básica com Linguagem C 3

A graduação é uma construção diária, requer tempo e dedicação,


e o tempo só promove aqueles que trabalham a seu favor.

Fonte: https://publicdomainvectors.org/photos/World-in-Hand-Small.png
Programação Básica com Linguagem C 4

Prefácio

Este livro tem como principal objetivo o de servir de texto para a disciplina de
Introdução à Programação do curso de Engenharia da Computação da Universidade
Federal do Vale do São Francisco.
Considerando que um programa de computador tem fundamento na lógica, é
impessoal, seus critérios são abstratos, generalizados e são dirigidos para a
resolução de problemas com vista a resultados objetivos.
Considerando que nosso cérebro, em especial o córtex cerebral, é "responsável
por descobrir padrões, raciocinar de modo lógico, prever o pior e preparar–se para
lidar com ele, criar tecnologia e transmiti–la através da cultura" (Suzana Herculano–
Houzel), este texto busca responder, para fins de aprendizagem, as questões:

• O que é algoritmo?
• O que é programa de computador?
• Como e quando usar os conceitos da linguagem de programação C.
• Como criar programas de computador para resolver problemas de engenharia.

Uma boa definição de Computador é máquina capaz de receber, armazenar,


recuperar e processar dados usando programas mantidos em sua memória.
Fazer programas de computador é escrever códigos fontes corretos, não é um
processo evidente por si só, requer consciência crítica, atenta, conhecedora daquilo
que se programa e requer esforço direcionado a resultados.
Embora sejam apenas letras, o código fonte é portador de uma dinâmica que lhe
é própria, que se tornará presente ao ser executado e, quem programa, deve
antecipá–la em detalhe no ato da escrita, no “passo a passo” de cada comando.
Os autores esperam que tenha contribuído com o ensino destes conteúdos de
modo a torná–los mais atraentes e aplicados nas diversas engenharias, quando
cabível.
Será apresentada a Senhora do Hardware: a Linguagem C. Com ela, o hardware
é o limite – tente fazer, se ela não fizer é porque o hardware não permite … ou
talvez seja porque você não tentou direito!
Não coloque limites neste texto! Amplie suas palavras e vá além … o além cada
um decide onde ele está ou é!
Programação Básica com Linguagem C 5

Este texto busca explicar melhor os conceitos da linguagem C e das boas


práticas e técnicas de programação, sendo um complemento dos livros textos da
disciplina, a saber:

Schildt, Herbert. C Completo e Total. 3a ed. Editora Pearson Makron


Books, 2006.

Ascenio, A. F. G.; Campos, E. A. V. Fundamentos da Programação de


Computadores. 2ª ed. Editora Pearson Education, 2003.

Sebesta, R. W. Conceitos de Linguagens de Programação. 9a ed.


Bookman, 2011.

Schildt, Herbert. C: The Complete Reference. 4th ed.


McGraw–Hill Education, 2000.

No texto, serão destacados os conceitos nele inseridos. Cada um de nós tem


maneiras diferentes de entender estes conceitos, uns entendem rápido, outros mais
devagar, também tem aquele que entendem de forma errada. A aplicação do
conceito ajuda a sua compreensão. A medida que outros conceitos vão surgindo, o
corpo de conhecimento da Programação em Linguagem C e a forma dos seus
Algoritmos vai se consolidando. É o processo humano de aprendizagem.

conceito – definição científica e/ou técnica que fundamenta o


conhecimento e a aplicação de um termo

É de extrema importância a construção do vocabulário científico e termos


técnicos e também desenvolver o costume de expressar com propriedade. Estas
capacidades e habilidades distingue o engenheiro do leigo, pode-se dizer que é o
seu verniz profissional.

vocabulário científico – conjunto de conceitos e termos de uma área


científica e sua expressividade linguística
termos técnicos – conjunto de conceitos e termos de uma área
técnico/científica e sua expressividade linguística

Muitas figuras e muito exemplos estão apresentados no texto e grande parte


deles estão discutidos. Boas figuras e bons exemplos de programa de computador
Programação Básica com Linguagem C 6

valem muitas palavras. Também pode ser inspiração para outros programas.

figuras – buscam explicar um recurso da Linguagem C e, as vezes, as


relações entres estes recursos
exemplos de programas – buscam mostrar como se aplica um
recurso da Linguagem C

Por fim os possíveis erros e seus cuidados.

informação sobre situação com potencial risco de erros

Deixo aqui minhas antecipadas desculpas por eventuais erros neste texto, que
certamente existem, agradeço antecipadamente toda e qualquer correção ou
sugestão de melhoramentos, que deverão ser enviadas para o e–mail do autor.
Serão colocadas na página
http://www.univasf.edu.br/~brauliro.leal/page/feedback.htm as Errata, Críticas e
Sugestões recebidas.
Programação Básica com Linguagem C 7

Índice
1. Introdução...............................................................................................................................................11
1.1. Computador.....................................................................................................................................11
1.2. O Sistema Operacional....................................................................................................................16
1.3. Programação de Computadores.......................................................................................................17
1.4. Programação Estruturada................................................................................................................24
2. Linguagens de Programação...................................................................................................................26
3. Compiladores C.......................................................................................................................................31
4. Linguagem C...........................................................................................................................................35
4.1. Visão Geral......................................................................................................................................35
4.1.1. A Função main.........................................................................................................................36
4.1.2. Bloco de Comando..................................................................................................................36
4.1.3. Estrutura Sequencial................................................................................................................37
4.1.4. Funções de Entrada/Saída (E/S)..............................................................................................37
4.2. Tipos de Dados................................................................................................................................39
4.2.1. Modificadores de Tipo de Dado..............................................................................................40
4.2.2. Tipo void..................................................................................................................................41
4.2.3. Tipo char..................................................................................................................................41
4.2.4. Tipo int....................................................................................................................................42
4.2.5. Tipos float e double.................................................................................................................44
4.2.6. Estrutura dos Tipos Simples....................................................................................................45
4.2.7. Tipos Estruturados...................................................................................................................48
4.2.8. Tipos Apontador......................................................................................................................48
4.2.9. Exercícios................................................................................................................................49
4.3. Constantes.......................................................................................................................................49
4.4. Variáveis..........................................................................................................................................51
4.4.1. Declaração...............................................................................................................................52
4.4.2. Leitura e Escrita de Variáveis..................................................................................................53
4.4.3. Escopo de Variáveis................................................................................................................59
4.4.4. Classe de Armazenamento de Variáveis.................................................................................61
4.5. Expressões.......................................................................................................................................62
4.5.1. Operadores Aritméticos e Lógicos..........................................................................................62
4.5.2. Precedência e Associatividade de Operadores........................................................................64
4.5.3. Expressões Lógicas..................................................................................................................64
4.5.4. Expressões Aritméticas............................................................................................................66
4.5.5. Operador de Atribuição...........................................................................................................67
4.5.6. Abreviaturas do Comando de Atribuição................................................................................69
4.5.7. Transbordamento de Dados.....................................................................................................70
4.5.8. Promoção de Tipo de Dado em Expressões............................................................................70
4.5.9. Cast..........................................................................................................................................72
4.5.10. Funções Matemáticas............................................................................................................74
4.5.11. Gerando Dados de Entrada....................................................................................................75
4.5.12. Estrutura e Estilo...................................................................................................................75
4.5.13. Resumo..................................................................................................................................75
4.5.14. Exercícios..............................................................................................................................76
4.6. Estrutura Condicional......................................................................................................................78
4.6.1. Comando if/else.......................................................................................................................78
4.6.2. Comando Ternário (?:)............................................................................................................84
4.6.3. Comando switch......................................................................................................................85
4.6.4. Exercícios................................................................................................................................88
4.7. Estrutura de Repetição....................................................................................................................92
Programação Básica com Linguagem C 8

4.7.1. Comando for............................................................................................................................94


4.7.2. Algoritmos Básicos..................................................................................................................99
4.7.3. Exercícios..............................................................................................................................104
4.7.4. Comando while......................................................................................................................107
4.7.5. Condições de Parada..............................................................................................................110
4.7.6. Exercícios..............................................................................................................................112
4.7.7. Comando do/while.................................................................................................................114
4.7.8. Exercícios..............................................................................................................................117
4.7.9. Comandos break e continue...................................................................................................118
4.7.10. Resumo................................................................................................................................119
4.8. Funções..........................................................................................................................................119
4.8.1. Escopo de Nomes e Tempo de Vida de Variáveis.................................................................121
4.8.2. Recursividade........................................................................................................................123
4.8.3. Recursividade x Interatividade..............................................................................................125
4.8.4. Protótipo de Função...............................................................................................................126
4.8.5. Resumo..................................................................................................................................127
4.8.6. Exercícios..............................................................................................................................127
4.9. Apontadores..................................................................................................................................128
4.9.1. Ponteiro..................................................................................................................................130
4.9.2. Ponteiros – Endereço x Valor................................................................................................132
4.9.3. Aritmética com Ponteiros......................................................................................................134
4.9.4. O conceito de NULL.............................................................................................................134
4.9.5. Comparação de Ponteiros......................................................................................................134
4.9.6. Ponteiro para Ponteiros..........................................................................................................135
4.9.7. Cuidado com os Apontadores!..............................................................................................136
4.9.8. Resumo..................................................................................................................................136
4.9.9. Exercícios..............................................................................................................................136
4.10. Dados Estruturados.....................................................................................................................138
4.10.1. Vetores.................................................................................................................................138
4.10.1.1. Algumas Operações com Vetores.................................................................................140
4.10.1.2. Aplicações com Vetores...............................................................................................140
4.10.1.3. Obtendo Máximo e Mínimo de Vetor...........................................................................145
4.10.1.4. Busca em Vetor.............................................................................................................147
4.10.1.5. Ordenação de Vetores...................................................................................................147
4.10.1.6. Vetor e Apontador........................................................................................................148
4.10.1.7. Vetor e Função..............................................................................................................148
4.10.1.8. Resumo.........................................................................................................................150
4.10.1.9. Exercícios – resolva usando funções e apontadores.....................................................150
4.10.2. Strings..................................................................................................................................155
4.10.2.1. Operações do Tipo de Dado string...............................................................................157
4.10.2.2. A Função main..............................................................................................................159
4.10.2.3. Vetor de strings.............................................................................................................160
4.10.2.4. Strings e Ponteiros........................................................................................................161
4.10.2.5. String e Função.............................................................................................................161
4.10.2.6. Resumo.........................................................................................................................161
4.10.2.7. Exercícios......................................................................................................................162
4.10.3. Matrizes...............................................................................................................................162
4.10.3.1. Aplicações com Matrizes..............................................................................................162
4.10.3.2. Operações com Linhas, Colunas e Diagonais de Matriz..............................................166
4.10.3.3. Multiplicação de Matrizes............................................................................................171
4.10.3.4. Classificação de Matriz.................................................................................................172
4.10.3.5. Matriz e Apontador.......................................................................................................172
Programação Básica com Linguagem C 9

4.10.3.6. Matriz e Função............................................................................................................172


4.10.3.7. Resumo.........................................................................................................................173
4.10.3.8. Exercícios......................................................................................................................173
4.10.4. Estruturas.............................................................................................................................177
4.10.5. União...................................................................................................................................183
4.10.6. Campo de bit........................................................................................................................183
4.10.7. Enumeração.........................................................................................................................184
4.10.8. Typedef................................................................................................................................184
4.10.9. Resumo................................................................................................................................185
4.10.10. Exercícios..........................................................................................................................185
4.11. Arquivos......................................................................................................................................185
4.11.1. Abertura de Arquivo............................................................................................................186
4.11.2. Fechamento de Arquivo.......................................................................................................188
4.11.3. Entrada/Saída em Arquivo...................................................................................................188
4.11.4. Arquivos stdin, stdout e stderr.............................................................................................196
4.11.5. Tratamento de Erros............................................................................................................196
4.11.6. Resumo................................................................................................................................198
4.11.7. Exercícios............................................................................................................................199
5. Alocação Dinâmica de Memória...........................................................................................................200
5.1. Memória Principal.........................................................................................................................200
5.2. Programas C e Memória Principal................................................................................................201
5.3. Alocação de Memória...................................................................................................................204
5.4. Vetores Estático x Dinâmico.........................................................................................................205
5.5. Vetor de Apontadores....................................................................................................................206
5.6. Resumo..........................................................................................................................................214
6. Biblioteca Padrão C..............................................................................................................................216
7. Aplicações.............................................................................................................................................218
7.1. Máximo Divisor Comum MDC....................................................................................................218
7.2. Números Primos............................................................................................................................219
7.3. Aplicações com Séries..................................................................................................................220
7.4. Exercícios......................................................................................................................................224
7.5. Recorrência em Séries...................................................................................................................224
7.6. Exercícios......................................................................................................................................226
7.7. Processamento de Texto................................................................................................................227
7.8. Cálculo Numérico Elementar........................................................................................................227
8. Preprocessamento..................................................................................................................................228
9. Ambiente de Desenvolvimento Integrado (IDE)..................................................................................229
9.1.1. Editoração, Compilação e Debug..........................................................................................232
9.1.2. Projetos de Sistemas..............................................................................................................232
10. Uso do Terminal..................................................................................................................................233
11. Makefile..............................................................................................................................................234
12. Sintaxe C em Backus-Naur Form.......................................................................................................235
13. Buscando Padrões para fins de Algoritmo..........................................................................................239
13.1. Soma: Humanos x Computador..................................................................................................243
13.2. Sim e Não: Humanos x Computador...........................................................................................243
13.3. Comparação: Humanos x Computador.......................................................................................244
13.4. Humanos x Computador..............................................................................................................244
13.5. Notas Adicionais sobre a Linguagem C......................................................................................244
13.6. Dado e Informação......................................................................................................................245
14. Anexos................................................................................................................................................247
14.1. Tabela ASCII...............................................................................................................................247
14.2. Pseudocódigo..............................................................................................................................249
Programação Básica com Linguagem C 10

14.3. Fluxograma..................................................................................................................................250
14.4. Formatos de E/S..........................................................................................................................251
14.5. Portas Lógicas.............................................................................................................................253
14.6. Revisão de Matrizes....................................................................................................................258
14.7. Palavras Reservadas da Linguagem C........................................................................................261
15. Terminologias Úteis............................................................................................................................263
16. Bibliografia.........................................................................................................................................265
Programação Básica com Linguagem C 11

1. Introdução

Desde o início de sua existência, o homem procurou criar máquinas que o


auxiliassem em seu trabalho, diminuindo o esforço e economizando tempo. Dentre
essas máquinas, o computador vem se mostrando uma das mais versáteis, rápidas
e seguras. Eles são produzidos em vários formatos e tamanhos, todos eles possuem
ao menos um processador, também conhecido como CPU.
O computador pode auxiliá–lo em muitas tarefas. E, embora, não tenha iniciativa
e nenhuma independência, não seja criativo e nem tenha inteligência como a
humana, pode receber instruções detalhadas e executá–las inúmeras vezes. A
mesma máquina pode executar ora um editor de texto, ora um jogo, ou os dois ao
mesmo tempo. Nisso reside a sua grande utilidade – ele é programável e
reprogramável – é versátil.
Os computadores possuem duas partes diferentes mas que trabalham juntas: o
hardware, composto pelas partes físicas, e o software, composto pelos programas.
No entanto, para que o computador execute esses programas, devemos escrevê–
los usando uma linguagem acessível tanto aos computadores quanto aos criadores
de softwares. Essa linguagem é chamada linguagem de programação, exitem
muitas delas, são linguagens próximas da linguagem humana mas que podem ser
traduzidas para a linguagem de máquina.

linguagem natural1 – linguagem falada por humanos


linguagem de programação – linguagem para humanos escreverem
programas de computador
linguagem de máquina – linguagem binária, usa as letras {0,1}
programa executável – programa de computador em linguagem
binária

1.1. Computador
Computadores são máquinas versáteis e permitem a execução de uma grande
1 Os termos linguagem natural, linguagem de programação, linguagem de máquina e programa executável possuem
definições mais rigorosa, estes aqui expressos são de ordem didática.
Programação Básica com Linguagem C 12

variedade de operações de acordo com suas capacidades. Por isso eles estão em
todos os lugares na sociedade moderna, onde as relações sociais podem ser
mediadas pela tecnologia, criando um mundo digital.

computador - máquina capaz de variados tipos processamento de


dados

A arquitetura de von Neumann é um modelo geral de Computador da


atualidade, e é usado para descrever o funcionamento do computador em termos
da interação entre três componentes:

1. unidade de processamento – realiza as operações matemáticas e lógicas


2. armazenamento de dados – memória de trabalho
3. dispositivos de entrada e saída – recebe e envia informações de/para o usuário

A estrutura geral de um computador é apresentado na Figura 1.1, os seus


componentes principais são o processador (CPU ou Unidade Central de
Processamento), a memória (RAM ou memória principal), o barramento (de dados,
de endereços e de controle) e os dispositivos de entrada/saída (E/S).
Estes componentes, em geral, são cartões de circuitos integrados inseridos na
placa–mãe ou periféricos conectados ao gabinete do computador. Este conjunto é o
hardware, os constituintes materiais do computador.

Figura 1.1 Estrutura geral de um computador e seus componentes (Arquitetura de


von Neumann).

fluxo de controle – e a sequência contínua e ordenada dos comandos


dos programas de computador do seu início ao seu fim

Os computadores modernos utilizam sistemas operacionais com interfaces


gráficas amigáveis e que permitem a execução de diversas funções e a instalação
de outros programas de computador tais como editores de texto, planilhas e
Programação Básica com Linguagem C 13

pacotes gráficos. Este conjunto é o software, os constituintes lógicos do


computador.

programa fonte – texto escrito em linguagem de programação


programa de computador – dependendo do contexto pode ser
programa executável ou programa fonte
software – termo bem genérico, programa fonte, programa de
computador ou programa executável

Na Figura 1.1 falta o Sistema Operacional, cuja função é carregar os programas


executáveis na memória e prover alguns serviços de intermediação entre software
e hardware. A carga de um programa executável na memória é o início de um
intenso fluxo entre os componentes do hardware, o chamado fluxo de controle.
O fluxo de controle percorre o programa do início ao fim, executando seus
comandos conforme definido pelo programador. O início é único mas pode haver
vários comandos encerrando esses programas.

use o seu dedo – pode-se percorrer os programas de computador com


um dedo e identificar seu fluxo de controle

A integração do Software com o Hardware dos computadores é feita através de


programas escritos em código de máquina ou linguagem de máquina, Figura 1.2.

Figura 1.2 A linguagem de máquina é a conexão entre o Software e o Hardware dos


computadores2.

A linguagem de máquina é binária, constituída de zeros (0) e uns (1). Desta


forma, os softwares que são executados pelos computadores são sequências de
números binários nas quais estão codificados dados e instruções para que possam
processar suas tarefas, Figura 1.2.
A Figura 1.3 é parte de um programa em linguagem de máquina, uma sequência
de 0 e 1, que são as letras do código de máquina, denominadas bits.

2 Fonte: https://locomotiva26.com.br/wp–content/uploads/2015/09/integracao–hardware–software–563x353.jpg
Programação Básica com Linguagem C 14

Figura 1.3 Parte de um programa em linguagem de máquina, composta por uma


sequência de bits.

Ler programas de computador em código de máquina não é tarefa fácil, como


pode ser visto na Figura 1.3, escrever programas usando o alfabeto dos bits
também não. Para facilitar a leitura bits, eles são organizados em grupos de 8 bits,
denominado byte, como pode ser visto na Figura 1.4.

Figura 1.4 Código binário organizado em bites.

Um byte é composto por 8 bits e cada bit pode ser 0 ou 1. Dessa forma pode
haver 256 (28) formas de arranjar bits para formar bytes. Para facilitar ainda mais a
leitura e a escrita do código de máquina foi criado o Código ASCII (American
Standard Code for Information Interchange ou Código Padrão Americano para o
Intercâmbio de Informação).
O Código ASCII é binário e codifica um conjunto de 256 sinais: 95 símbolos
gráficos (letras do alfabeto latino, sinais de pontuação e sinais matemáticos) e 33
sinais de controle, Tabela 14.1 do Anexo. Outros 128 sinais compõem a parte
estendida deste código, Tabela 14.2 do Anexo.
A codificação ASCII é usada para representar textos em computadores,
Programação Básica com Linguagem C 15

equipamentos de comunicação, entre outros dispositivos que trabalham com texto.


Os sinais não–imprimíveis, conhecidos como caracteres de controle, são
amplamente utilizados em dispositivos de comunicação e afetam o processamento
do texto.

Exemplo 1.1 Escrever a palavra bit em código de máquina utilizando o código


ASCII.
Utilizando a Tabela 14.1 pode–se obter ver o equivalente binário de cada letra:
b => 01100010
i => 01101001
t => 01110100
Logo, a palavra bit em código de máquina é 01100010 01101001 01110100.
bit => 011000100110100101110100

Observe na Tabela 14.1 que as letras maiúsculas precedem as minúsculas no


código ASCII. Os primeiros programas de computador eram escritos utilizando letras
maiúsculas. Com a evolução das linguagens de programação, as letras minúsculas
foram incorporadas aos softwares.

Exemplo 1.2 Escrever a expressão C=A+B em código de máquina.


Utilizando a Tabela 14.1 pode–se obter o equivalente binário de cada letra:
C => 01000011
= => 01011101
A => 01000001
+ => 00101011
B => 01000010
Logo, C=A+B em código de máquina é 0100001101011101010000010010101101000010.
C=A+B => 0100001101011101010000010010101101000010

Seguem exercícios.

Exercício 1.1 Escrever as expressões em código de máquina:


1. for(i=0;i<10;i++)printf(“%d”,i);
2. x=2*y–x/5;
3. z=A*x+B;
4. int main(void){}

Exercício 1.2 Escrever as expressões correspondentes aos códigos de máquina:


1. 0100000101010011010000110100100101010011
2. 0111011100111101001100100010101000101000010000010010111100101011010000100
01011110010100100111011
3. Figura 1.4
Programação Básica com Linguagem C 16

Exemplo 1.3 Para representar nosso conhecimento usamos símbolos, leia este
texto.
50M05 53R35 QU3 49R3ND3 3 R39R353N74M05 N05505 C0NH3C1M3N705 90R
M310 D3 51M80L05. 4 M473M471C4 3 UM 6R4ND3 3X3M9L0, 70D05 C0NH3C3M
53U5 51M80L05 QU3 540 4D074D05 90R 70D45 45 CUL7UR45. 0 M35M0 V4L3
94R4 4 MU51C4, 05 51N415 D3 7R4N5170, 05 M4945, 05 1C0N35 D05
9R06R4M45 D3 C0M9U74D0R. 3 MU170 M415. 3NC0N7R3 V0C3 0U7R05
3X3M9L05. 3573 73X70 3574 35CR170 3M 51M80L05, N40 3 F4C1L D3 49R3ND3R
3 3N73D3R? 9R06R4M4R 74M83M U54 51M80L05 C0M0 3573, 3 MU170 F4C1L D3
49R3ND3R 74M83M.

1.2. O Sistema Operacional


Os Sistema Computacionais evoluem muito rapidamente, atualmente são
constituídos de um ou mais processadores, memória principal, discos, impressoras,
teclado, mouse, monitor, interfaces de rede e outros dispositivos de entrada e
saída.
Os Sistema Computacionais são complexos e o Sistema Operacional (SO) é o
gerente dos recursos da máquina.

Sistema Operacional (SO) é um conjunto softwares com a função de


gerenciar os recursos da máquina e fornecer uma interface entre o
computador e o usuário.

A Figura 1.5 mostra o Modelo de Computador abstrato fornecido pelo Sistema


Operacional, destacando sua grande simplificação, onde o usuário interage
diretamente apenas com o software em uso, e o SO assumindo as demais tarefas
do sistema.

Figura 1.5 Modelo de Computador fornecido pelo Sistema Operacional.

Os principais recursos gerenciados pelo SO são:


Programação Básica com Linguagem C 17

• processos – interrupção de hardware e segurança (proteção de memória e de


processos)
• memória – memória principal e secundária (discos rígidos, pendrive)
• recursos – drives de dispositivos como teclado e monitor
• entrada e saída de dados – teclado, monitor de vídeo, interfaces de rede e
impressora
• sistema de arquivos – leitura/escrita em arquivos, copiar/gravar/remover arquivos

1.3. Programação de Computadores


Os conceitos de Algoritmo são muitos, o mesmo pode ser dito sobre os conceitos
de Programa de Computador e de Linguagem de Programação. Abaixo estão um
conceito para cada um deles.

Algoritmo é conjunto das regras e procedimentos lógicos bem


definidos que levam à solução de um problema em um número finito
de etapas.
Programa de Computador é um conjunto de instruções que
descrevem uma tarefa a ser realizada por um computador.
Linguagem de Programação é um método padronizado, formado
por um conjunto de regras sintáticas e semânticas, para implementar
código fonte que pode ser convertido em programa de computador.
Há outros conceitos e definições para Algoritmo, Programa de Computador e
Linguagem de Programação, procure na internet para esclarecimentos.

Programa de Computador é um produto feito na imaginação (meu


conceito).

Algoritmos, Programa de Computador e Linguagem de Programação estão muito


relacionados. Como indicam a Figura 1.6 e os fatos abaixo:

• Nem todo Algoritmo pode se tornar um Programa de Computador


• Todo Programa de Computador pode se tornar um Algoritmo
• Todo Programa de Computador pode ser escrito em uma Linguagem de Programação

Figura 1.6 Relação entre Algoritmos, Programa de Computador e Linguagem de


Programação Computador.

Por enquanto, os algoritmos dos Exemplo 1.4 e Exemplo 1.5 não podem ser
transformados em Programa de Computador mas o Exemplo 1.6 pode.
Programação Básica com Linguagem C 18

Exemplo 1.4 Manual para a montagem de uma Cadeira Eames Plus.

Fonte: GL BR – Manual Cadeira Eames Plus.cdr


Este manual é um exemplo de algoritmo. Pode–se observar algumas
características deste algoritmo:

1. Temos duas partes, os ingredientes (peças, ferragens e ferramentas) e as


instruções
2. Tanto os ingredientes quantos as instruções são em número finito; temos 7
ingredientes e 4 instruções
3. Tem início e fim
4. É completo o suficiente para montar a cadeira a partir dos ingredientes
5. É detalhado o suficiente para montar a cadeira a partir dos ingredientes; nem mais
nem menos – pelo menos para seres humanos
6. Cada instrução é bem definida

Ouso afirmar que, de posse dos ingredientes, qualquer ser humano é capaz de
montar a citada cadeira a partir do algoritmo.

Segue outro exemplo de algoritmo.

Exemplo 1.5 Receita para fazer Bolo Simples.

Ingredientes Modo de Preparo


Programação Básica com Linguagem C 19

• 2 xícaras (chá) de açúcar 1. Bata as claras em neve e reserve


• 3 xícaras (chá) de farinha de trigo 2. Misture as gemas, a margarina e o
• 4 colheres (sopa) de margarina açúcar até obter uma massa
• 3 ovos homogênea
• 1 e 1/2 xícara (chá) de leite 3. Acrescente o leite e a farinha de
• 1 colher (sopa) bem cheia de trigo aos poucos, sem parar de
fermento em pó bater.
4. Por último, adicione as claras em
neve e o fermento
5. Despeje a massa em uma forma
grande de furo central untada e
enfarinhada
6. Asse em forno médio 180 °C,
preaquecido, por aproximadamente
40 minutos ou ao furar o bolo com
um garfo, este saia limpo
Fonte: https://www.tudogostoso.com.br/receita/29124–bolo–simples.html
Esta receita é um exemplo de algoritmo. Pode–se observar algumas características
deste algoritmo:

1. Temos duas partes, os ingredientes e as instruções (modo de preparo)


2. Tanto os ingredientes quantos as instruções são em número finito; temos 6
ingredientes e 6 instruções
3. Tem início e fim
4. É completo o suficiente para fazer o bolo simples a partir dos ingredientes
5. É detalhado o suficiente para fazer o bolo simples a partir dos ingredientes; nem
mais nem menos – pelo menos para seres humanos
6. Cada instrução é bem definida

Ouso afirmar que, de posse dos ingredientes, qualquer ser humano é capaz de
fazer o citado bolo a partir do algoritmo.

Segue mais outro exemplo de algoritmo.

Exemplo 1.6 Algoritmo para somar dois números usando uma calculadora comum.

1. Digite o primeiro número com o teclado da calculadora


2. Comprimir a tecla referente à operação somar
3. Digite o segundo número com o teclado da calculadora
4. Comprimir a tecla referente ao igual
5. Leia o resultado no visor da calculadora

Segue o algoritmo para calcular os dígitos verificadores de CPF.

Exemplo 1.7 Algoritmo para calcular os dígitos verificadores de CPF


O CPF é composto por 9 dígitos além de dois dígitos verificadores, que são
calculados.
Programação Básica com Linguagem C 20

O primeiro dígito verificador é calculado a partir dos 9 dígitos do CPF.


O segundo dígito verificador é calculado a partir dos 9 dígitos do CPF,
acrescentando a ele o primeiro dígito verificador. Da seguinte forma:

1. multiplique cada um dos 9 dígitos do CPF, da direita para a esquerda, por


números inteiros consecutivos a partir do número 2
2. some as parcelas do item anterior
3. tome o resto da divisão da soma por 11
4. se o resto for menor do que 2 então o primeiro dígito verificador é igual a 0
(zero) caso contrário é igual a 11 menos o resto
5. Acrescente o primeiro dígito verificador aos dígitos do CPF e repita os
procedimentos anteriores para calcular o segundo dígito verificador

Este algoritmo pode ter outras redações além da apresentada.

Algoritmos envolvendo cálculos e fórmulas matemáticas são mais fáceis de


desenvolver pois há muito menos ambiguidade na redação das tarefas. Elas tem a
clareza da matemática. Analise o algoritmo de Euclides para obter o MDC – Máximo
Divisor Comum que está no Exemplo 1.8.

Exemplo 1.8 Algoritmo de Euclides para obter o MDC de dois números

1. Dados dois números A e B, divida A por B e obtenha o resto R1


2. Se o resto R1 for zero, então o MDC de A e B é B
3. Se R1 for diferente de zero, divida B por R1 e obtenha o resto R2
4. Se o resto R2 for zero, então o MDC de A e B é R1
5. Se R2 for diferente de zero, então divida R1 por R2 e obtenha o resto R3
6. Se o resto R3 for zero, então o MDC de A e B é R2
7. Se R3 for diferente de zero, repita os dois passos anteriores até que o novo resto
obtido seja igual a zero

Os algoritmos de interesse computacional podem ser representados de duas


formas, semelhantes ao modo como os programas são escritos: Fluxograma e
Pseudocódigo.
O Fluxograma é menos detalhista do que o Pseudocódigo. Tem a vantagem de
ser gráfico e indicar com grande clareza o fluxo de controle do algoritmo.
O Pseudocódigo é textual e os algoritmos nele representados podem ser
traduzidos, quase que diretamente, para uma linguagem de programação.
No Anexo são apresentados o Pseudocódigo e o Fluxograma.
E Exemplo 1.9 é um Fluxograma de um dia típico de um estudante. Neste
fluxograma, pode-se ver as estruturas sequencial, condicional e de repetição.
Reproduza o fluxo de controle deste exemplo usando a Regra do Dedo.
Programação Básica com Linguagem C 21

Exemplo 1.9 Fluxograma de um dia típico de um estudante

O Exemplo 1.10 é algoritmo para validar CPF em Pseudocódigo, no caso em


Portugol. Neste pseudocódigo, pode-se ver as estruturas sequencia, condicional e
de repetição. Observe os detalhes desta representação, há declarações e
identificação de tipos. Reproduza o fluxo de controle deste exemplo usando a Regra
do Dedo.

Exemplo 1.10 Algoritmo em Portugol para validação de CPF


Algoritmo: ValidaCPF
var
cpf : caracter
n_cpf :vetor[1..11] de inteiro
soma1 :vetor [1..9] de inteiro
soma2 :vetor[1..10] de inteiro
s1 :inteiro
s2 :inteiro
x :inteiro
resto1 :inteiro
resto2 :inteiro
inicio
escreval("*******TESTE DE VALIDAÇÃO!*******")
escreval("Digite o CPF:")
leia(cpf)
para x de 1 ate 11 faca
n_cpf[x] := caracpnum(copia(cpf,x,1))
fimpara
Programação Básica com Linguagem C 22

para x de 1 ate 9 faca


soma1[x] := n_cpf[x]*(11-x)
s1 := s1+soma1[x]
fimpara
resto1 := s1 mod 11
se( resto1 < 2 ) então
resto1 := 0
senao
resto1 := 11-resto1
fimse
para x de 1 ate 10 faca
soma2[x] := n_cpf[x]*(12-x)
s2 := s2 + soma2[x]
fimpara
resto2 := s2 mod 11
se( resto2 < 2 ) então
resto2 := 0
senao
resto2 := 11-resto2
fimse
se( resto1 = n_cpf[10] ) e ( resto2 = n_cpf[11] ) então
escreva( cpf," Esse Cpf é Valido" )
senao
escreva( cpf," Esse Cpf não é Valido!" )
fimse
fimalgoritmo

A Engenharia de Software é uma especialidade voltada para o desenvolvimento


de software, normalmente grandes projetos envolvendo programação.
Cada indivíduo possui sua forma de resolução de problema. Na área científica a
solução dos problemas deve ser padronizada para facilitar o entendimento por
outras pessoas e também possibilitar a reprodução das nossas soluções.
O matemático George Polya propõe um método estruturado para a resolução de
problemas baseado em quatro etapas:

1. Entender – deve-se obter a melhor compreensão do problema, identificando quais


são as questões e variáveis existentes e verificando se existem informações
suficientes para entendê-lo, e buscar uma solução.
2. Planejar - consiste em estudar a melhor forma de resolver o problema. É
basicamente identificar o melhor método a ser aplicado; geralmente o método da
divisão em problemas menores auxilia nesse processo. Algumas técnicas comuns a
serem utilizadas nessa etapa são: intuição, lista ordenada, eliminação de
possibilidades, simetria e semelhança com outros casos, causa e efeito, análise
sistêmica, estruturação de uma equação, desenhos, busca por padrões etc.
Programação Básica com Linguagem C 23

3. Executar - consiste em executar o plano realizado na etapa anterior e efetivamente


solucionar o problema.
4. Verificar – deve-se verificar a solução encontrada. Para isso, necessário validar
todas as entradas possíveis apresentadas no problema e identificar possíveis pontos
de falhas.

De forma muito simplificada, a construção de algoritmos envolve passos


similares, como os abaixo relacionados:

1. Compreender o problema a ser resolvido, destacando os pontos importantes e sua


composição
2. Definir os dados de entrada e os demais dados que fazem parte do problema
3. Definir o processamento, os cálculos a serem efetuados para transformar dados de
entrada em dados de saída
4. Definir os dados de saída, os dados a serem gerados pelo processamento
5. Conceber testes para verificar e validar o algoritmo

Estes passos podem ser especificados ao identificar as operações e ações a


serem executadas sobre os dados para obter o resultado final esperado. Os
algoritmos mais simples possuem um conjunto de ações como os da Tabela 1.1.
Cada uma destas ações são desdobradas em um ou mais comandos para definir o
fluxo de controle e compor os programas de computador.

Tabela 1.1 Principais ações dos algoritmos mais simples


• início
• declaração das variáveis e constantes
• entradas de dados
• cálculos de expressões e atribuições
• decisões através de comparações
• repetições através de comparações
• saídas de dados
• fim

Pode–se observar que pessoas e computadores são muito diferentes, mas eles
precisamento se comunicar, o que leva a necessidade de linguagens de
programação com diferentes níveis. Os processadores normalmente executam
instruções simples e elementares e usam linguagens de baixo nível – aquelas mais
próximas das linguagens de máquina. As linguagens de máquina são consideradas
difíceis de programar e, portanto, foram criadas as linguagens de alto nível para
tornar mais fácil a tarefa de programação de computadores.
Como computadores não podem fazer julgamentos e nem resolver
ambiguidades, as linguagens de programação devem ser capazes de comunicar
instruções de forma precisa. Em geral, elas são muito mais simples do que as
linguagens humanas, denominadas linguagens naturais.
As Linguagens de Programação foram criadas para comunicar instruções para
computadores. Elas possuem uma gramática e um dicionário que formam um
Programação Básica com Linguagem C 24

conjunto de regras sintáticas (forma) e semânticas (significado) usadas para


escrever programas para computadores. Programas para computadores são
construídos a partir de algoritmos que, por sua vez, são sequências de instruções
ou operações padronizadas para resolver problemas.
Linguagens de programação são métodos padronizados para implementar
códigos que podem ser transformados e processados por computadores. São
constituídas de palavras, compostos de acordo com regras, para o código fonte de
softwares, que depois de serem traduzidos para código de máquina, e serem
executado por microprocessadores. Ou seja, elas podem ser usadas para expressar
algoritmos com precisão.
Quem faz uso de linguagens de programação são serem humanos, elas servem
para especificar programas com instruções para computadores agir, armazenar e
transmitir dados. As linguagens de programação também evoluem e são
classificadas em gerações, algumas delas são descritas abaixo:

• Primeira Geração – Linguagem de Máquina, programas em código binário com


instruções que o processador é capaz de executar, única para cada tipo de CPU.
• Segunda Geração – Linguagens de Montagem (Assembly), programas em código
mnemônico, que são símbolos em lugar dos bits, também única 3 para cada tipo de
CPU.
• Terceira Geração – Linguagens Procedurais, programas em código com suporte ao
conceito de procedimento, próximo da linguagem natural, o mesmo código pode ser
usado para todo tipo de CPU.
• Quarta Geração – Linguagens de Aplicação, programas em código com suporte ao
conceito de domínio específico, como banco de dados.
• Quinta geração – Linguagens voltadas a Inteligência Artificial.

1.4. Programação Estruturada


A programação estruturada permite elaborar códigos por meio de apenas três
estruturas: sequencial, condicional e de repetição, Figura 1.7.
Estas estruturas são suficientes para gerenciar o fluxo de controle nos
programas de computador, pode-se afirmar que são os ingredientes básicos de todo
e qualquer programa deste livro.

Figura 1.7 Fluxogramas das estruturas sequencial, condicional e de repetição.


3 Um programa escrito em linguagem assembly para uma CPU poderá não ser executado em outra CPU de uma família
diferente.
Programação Básica com Linguagem C 25

Estas estruturas simples são agrupadas em sub–rotinas e funções para a


produção de programas de computadores.
A programação estruturada tem sido usada há décadas para produção de
software grandes e pequenos, tais como sistemas operacionais, banco de dados e
compiladores. A programação estruturada é uma maneira de produzir software,
denominado paradigma de programação estruturada. Há outros paradigmas para a
produção de software, como paradigma de programação orientado a objetos,
paradigma de programação imperativa e paradigma de programação funcional.
Programação Básica com Linguagem C 26

2. Linguagens de Programação

Existem milhares de linguagens de programação e novas são criadas sempre


que necessárias. Embora em grande número e variadas, as linguagens de
programação, em geral, seus elementos constituintes podem reduzidos a:

1. palavras reservadas
2. símbolos
3. regras para dar significado aos seus elementos, seus usos e combinações

Conforme pode ser visto na Figura 1.1, qualquer que seja a linguagem de
programação, ela deve ser capaz de produzir programas para gerenciar o fluxo de
controle nos Barramento de Dados, Endereços e Controle. Para isso, elas possuem
vários elementos que estão discutidos na Tabela 2.1.

Tabela 2.1 Principais elementos das Linguagens de Programação


Palavras Reservadas
São palavras usadas para redigir os programas de computadores, com suas
sequências, decisões, repetições, sub–rotinas e funções.
Comentário
São textos explicativos colocados ao longo dos programas de computadores, são
ignorados no processo de tradução para o código de máquina.
Tipos de Dados
Os tipos de dados é uma combinação envolvendo valores e operações. Cada tipo é
identificado por cinco elementos básicos, quais sejam:
1. tipo de dado – nome do tipo de dado aceito pela linguagem
2. tamanho – quantidade de bytes armazenados na memória
3. estrutura – organização interna dos bits, seu significado e sua interpretação
4. faixa de variação – limite inferior, limite superior e intervalo de variação
5. operações – operações suportadas e seus operadores

De modo geral, os tipos básicos de dados são os literais, ponto fixo e ponto
flutuante.
Programação Básica com Linguagem C 27

Os tipos de dados literais tem tamanho reduzido, de um ou dois bytes, estrutura


simples com e sem sinal, variam de 1 e 1, são partes do conjunto dos números
inteiros. Possuem pequena faixa de variação. Suas operações matemáticas são
muito limitadas, podem ser operados como parte de textos, são usados para
representar símbolos da linguagem natural, como letra e números.
Os tipos de dados ponto fixo, com quatro ou oito bytes, possuem estrutura simples
com e sem sinal, variam de 1 e 1, são partes do conjunto dos números inteiros.
Possuem grande faixa de variação. Suas principais operações matemáticas são {+
- * % / }, a divisão exclui a parte fracionária.
Os tipos de dados ponto flutuante, com quatro ou oito bytes, possuem estrutura
complexa e possuem sinal, variam por frações da unidade, são partes do conjunto
dos números reais. Possuem grande faixa de variação. Suas principais operações
matemáticas são {+ - * / }, a divisão inclui a parte fracionária, e também as
funções matemáticas usuais, como potenciação, radiciação, trigonométricas,
exponenciais e logarítmicas.
Algumas linguagens possuem um tipo de dado especial capaz de representar
endereços de memória e operar sobre eles, são os apontadores.
Os tipos de dados orientam também como o programa os armazena na memória
do computador e também como eles são processados pela CPU.
Há também os tipos de dados estruturados, formados a partir do simples, como
vetores, matrizes e registros, dentre outros.
Constantes e Variáveis
Durante o desenvolvimento do programa é necessário criar variáveis, que são
compostas por quatro elementos básicos, a saber:
1. identificador – nome da variável, para possibilitar sua utilização
1. tipo de dados – tipo de dado da variável, que inclui as operações que podem ser
feitas com ela
2. valor – quantidade atribuída à variável ou obtida por meio de expressões
3. endereço – região da memória alocada para a variável

Ao executar os programas, os nomes das variáveis são transformados em


endereços de memória e seus valores tornam–se conteúdos de memória. Ou seja,
existem dois mundos da programação, aquele do par {identificador, valor} e o
outro par {endereço, conteúdo}.
O computador identifica cada variável por meio de um endereço e as linguagens
de programação permitem nomear cada endereço ou posição de memória,
facilitando a referência ao seu endereço.
Na programação, variáveis são capazes de reter e representar um valor ou
expressão.
Tecnicamente falando, variável é uma região de memória de um computador
previamente identificada e cuja finalidade é armazenar dados de um programa por
um determinado espaço de tempo e também as operações que podem ser feitas
com ela.
Vale destacar que a memória pode armazenar um conteúdo por vez e, quando o
computador altera a memória, o conteúdo que antes estava armazenado é perdido
ao dar lugar ao novo.
A diferença entre variáveis e constantes é que as variáveis podem ter seus dados
alterados, já as constantes retém seu valor durante todo tempo de execução do
programa; mas ambas possuem {identificador, tipo de dado, valor, endereço}.
Como já visto, programas representam soluções para um problema escrito em
Programação Básica com Linguagem C 28

linguagem de computador e, assim, é comum dividir os problemas em partes 4 e,


cada parte, ser representado por uma variável. As variáveis são elementos básicos
na programação, pois são elas que armazenam os dados necessários para a sua
elaboração. Dada a variedade de problemas tratados por computador, é necessário
criar muitas variáveis e ter muitos tipos de dados para representar seus valores.
Como há muitas linguagens de programação, algumas exigem a declaração das
variáveis do programa, outras não. Outras exigem que as variáveis tenha um tipo
bem definido outras não.
Expressões Aritméticas e Lógicas
O conceito de expressão na computação é muito similar ao da matemática, elas
são formadas variáveis e constantes (denominados operandos) que se relacionam
por meio de operadores. Os operadores podem ser classificados em aritméticos,
relacionais e lógicos, dando origem às expressões aritméticas, relacionais e lógicas
respectivamente que, uma vez avaliada, produz um resultado, em geral um valor.
Pode haver expressões mistas de acordo com as necessidades do programa.
Há ainda o operador de atribuição, aqui simbolizado por =, para sentenças da
forma variável = expressão, um dos comandos ou instruções mais simples das
linguagens de programação.
Há ainda regras para avaliar expressões, que podem incluir o uso de parêntesis
para estabelecer a ordem dos cálculos, além da definição da hierarquia dos
operadores, que varia entre as linguagens, normalmente a mesma da matemática.
Dependendo da linguagem, há também expressões literais, similares às já
mencionadas acima.
Estrutura Sequencial
Na computação, uma estrutura sequencial é um fluxo de controle presente em
linguagens de programação, que realiza um conjunto predeterminado de
comandos ou instruções de forma sequencial, de cima para baixo, uma a uma, na
ordem em que foram postas.
O fluxo de controle das estruturas sequencial não apresenta desvios, todos os
comandos são executados, de acordo com sua sequência.
Em geral, os comandos destas estruturas são separadas por algum tipo de
delimitador, que varia entre as linguagens.
Estrutura Condicional
As estruturas condicionais ou de decisão permitem saltos ou desvio de comandos,
fazendo com que o programa proceda de uma ou outra maneira, de acordo com os
resultados de suas decisões lógicas.
Uma estrutura condicional realiza um único desvio, faz uma única escolha.
Toda estrutura condicional possui uma expressão (denominada condição) que,
quando avaliada, permite decisão de fazer ou não fazer o desvio programado.
As principais comandos para estruturas condicionais são: se/então/senão e
switch/case. O formato dos comandos das estruturas condicionais variam entre
as linguagens de programação.
Estrutura de Repetição
As estruturas de repetição permitem que um grupo de comandos seja executado
um número definido ou indefinido de vezes, de acordo com os resultados de suas

4 Dividir para conquistar é uma técnica útil de resolução de problema, de origem militar; mas deve ser usada com cuidado
pois há muitos problemas que possuem sinergia entre suas partes e, nestes, o todo é maior que a soma de suas partes – e
esta técnica é de pouca utilidade.
Programação Básica com Linguagem C 29

decisões lógicas.
Uma estrutura de repetição pode executar várias vezes seu bloco de comandos.
Toda estrutura de repetição possui uma expressão (denominada condição) que,
quando avaliada, permite a decisão de executar ou não executar o bloco de
comandos programado.
As principais comandos para estruturas de repetição são: para e enquanto/faça e
faça/enquanto.
O comando para é usado para executar um número definido de repetições. Ele
possui um contador automático para este fim.
O comando enquanto/faça avalia sua condição e pode ou não executar seu bloco
de comandos, ou seja, ele pode executar seu bloco de comandos uma única vez,
nenhuma vez ou várias vezes.
O comando faça/enquanto avalia sua condição e executa seu bloco de comandos
ao menos uma vez, ou seja, ele pode executar seu bloco de comandos uma única
vez ou várias vezes.
O formato dos comandos das estruturas de repetição varia entre as linguagens de
programação.
Sub–Rotinas e Funções
As sub–rotinas são blocos de comandos que recebem um nome para identificá–la e
permitir seu uso. Dessa forma, as sub–rotinas permitem organizar um programa
em módulos, agrupando as tarefas repetitivas presentes no programa, deixa–o
melhor estruturado. Os módulos que retornam valor são denominadas funções,
caso contrário são denominados sub–rotinas.
Compiladores
Um compilador é um programa de computador que traduz um programa de uma
linguagem textual facilmente entendida por um ser humano para uma linguagem
de máquina, específica para um processador e sistema operacional.
O código original é denominado programa–fonte ou código fonte, em geral escrito
no formato texto e legível por seres humanos.
O código final é denominado programa executável ou código de máquina, em geral
escrito no formato binário que pode ser executados por um processador.
Como há variados tipos de processadores e sistemas operacionais, também há
vários compiladores para uma mesma linguagem de programação, um compilador
para cada combinação processador/sistemas operacional.
Interpretadores
Interpretadores são programas de computador que leem um código fonte de uma
linguagem de programação e o converte, em geral linha a linha, em código
executável.
Como há variados tipos de processadores e sistemas operacionais, também há
vários interpretadores para uma mesma linguagem de programação, um
interpretador para cada combinação processador/sistemas operacional.
Existem também, as linguagens de script, que são linguagens interpretadas,
executadas do interior de programas e de outras linguagens de programação como
em navegadores web.
Notas:

• Grosso modo, pode–se pensar que os dados e as expressões aritméticas e lógicas,


compõem as informações que trafegam no Barramento de Dados. Dados utilizados
Programação Básica com Linguagem C 30

para representar endereços de memória trafegam no Barramento de Endereços. E as


estruturas sequencial, condicional e de repetição, com as sub–rotinas e funções,
trafegam no Barramento de Controle. O trabalho conjunto destes barramentos
organizam o fluxo de controle que os computadores requerem para executarem seus
programas.
• As estruturas sequenciais, condicional e de repetição podem ser agrupadas por bloco
de comandos dentro ou fora das sub–rotinas e funções. As estruturas e as sub–
rotinas e funções podem também ser agrupadas em arquivos de tipo texto para
compor um programa–fonte.
• Teoricamente, qualquer linguagem pode ser compilada ou interpretada e,
dependendo da necessidade, pode ser melhor criar um interpretador ou um
compilador; há algumas linguagens que possuem ambas implementações.
• As linguagens de programação servem como intermediário entre a linguagem
humana e a linguagem de máquina, e devem atender tanto humanos quanto
computadores.
Programação Básica com Linguagem C 31

3. Compiladores C

O GNU Compiler Collection (chamado usualmente GCC) é um conjunto de


compiladores de linguagens de programação, sendo uma das ferramentas
essenciais para manter o software livre, pois permite compilar o código–fonte em
binários executáveis para as várias plataformas de hardware e sistemas
operacionais, como UNIX, Linux, Windows e Mac OS. Ele é distribuído pela Free
Software Foundation (FSF) sob os termos da GNU GPL (https://gcc.gnu.org/).
O GCC é frequentemente eleito o compilador preferido para desenvolver
software que necessita de ser executado em vários tipos de hardware. Ao usar os
compiladores do projeto GCC, o mesmo analisador gramatical é usado em todas as
plataformas, fazendo com que o se o código compila numa, muito provavelmente
compilará em todas.
A "Linguagem C" e a "Biblioteca Padrão C" são duas entidades separadas mas
que trabalham juntas. É necessário aprender a programar em C, por outro lado é
preciso aprender a usar a Biblioteca Padrão C. Ambas são padrão ANSI5.
A Linguagem C é definida pelas regras gramaticais (léxico6, sintaxe7 e
semântica8), declarações, tipos de dados, criação de variáveis, operações e
operadores, delimitadores, caracteres especiais, comandos, estruturas condicional
e de repetição, manipulação de apontadores, criação de funções e estrutura
modular, dentre outros. É uma linguagem de programação compilada de propósito
geral, estruturada, imperativa, procedural, padronizada pela Organização
Internacional para Padronização (ISO). Foi criada em 1972 por Dennis Ritchie. É
classificada como sendo de Terceira Geração9.
A Biblioteca Padrão da Linguagem C (também conhecida como glibc) é uma
biblioteca de funções padronizada da Linguagem C, que fornece um conjunto básico
de operações matemáticas, manipulação de cadeias de caracteres, conversão de
tipos de dados, tempo e fuso horário, sistema de arquivos, tratamento de erros,
dentre outras. Ela consiste de 24 cabeçalhos, cada um contendo uma ou mais

5 American National Standards Institute (https://www.ansi.org/)


6 Léxico é o conjunto de palavras existente à disposição da linguagem.
7 A sintaxe é a forma de dispor as palavras nos comandos e de dispor os comandos no programa, incluindo a sua relação
lógica e também suas combinações para fins de resolução de problemas.
8 A semântica descreve as estruturas da linguagem e seu comportamento nos programas e no hardware.
9 Com recursos das Linguagens de Segunda Geração, que lhes dá grande poder sobre o hardware.
Programação Básica com Linguagem C 32

declarações de funções, tipos de dados e macros 10. Ela é uma caixa de ferramentas
prontas para uso.

Figura 3.1 As linguagem e bibliotecas da GNU Compiler Collection.

A Linguagem C e a Biblioteca Padrão C serão estudadas nos próximos capítulos.


O Compilador GNU C gera programas executaveis em três etapas, Figura 3.2.
Partindo do programa–fonte escrito em C, que, didaticamente, será nomeado
arquivo.c, seguem as etapas:

1. Preprocessamento – são incluídos os cabeçalhos da biblioteca padrão, ampliando o


arquivo.c original
2. Compilação – o arquivo.c ampliando é traduzido para o seu equivalente em código
de máquina, e é gerado o código objeto de nome arquivo.o
3. Linkedição – os binários da Biblioteca Padrão são incluídos no código objeto
arquivo.o, produzindo o programa executável arquivo.exe (Windows) ou arquivo
(Linux)

Figura 3.2 Processo de produção de programa executável a partir do programa–


fonte, feito pelo GNU C.

O programa executável é um arquivo binário, um programa completo e


autossuficiente, podendo ser executado quando carregado na memória RAM pelo
Sistema Operacional.

10 Uma das instruções da Linguagem C


Programação Básica com Linguagem C 33

Figura 3.3 Visão resumida do processo de produção de programa executável a


partir do programa–fonte, feito pelo GNU C.

O SO é a ponte entre os programas executáveis e a máquina, Figura 3.4. Nesta


figura, as setas indicam a comunicação entre as camadas do computador, quando
elas prestam e recebem serviços umas das outras durante o tempo de execução do
programa executável.

Figura 3.4 Esquema das camadas de um computador.

Ao carregar um programa executável na memória RAM, ele organiza sua


memória de trabalho criando quatro regiões logicamente distintas. Embora o layout
físico destas regiões de memória difere entre os tipos de CPU e implementação da
linguagem C, Figura 3.5, a descrição a seguir mostra conceitualmente como
programas C utilizam a memória.
Heap – esta região é dinâmica e de uso livre, é utilizada por mecanismos de
alocação dinâmica de memória
Stack – é uma região dinâmica pois varia conforme a execução do programa. É
utilizada para armazenar endereços e passar parâmetros nas chamadas de funções,
armazenar variáveis locais ou ser manipulada enquanto o programa é executado
Global – a região de dados corresponde à área onde as variáveis globais e
estáticas são armazenadas;
Program Code – essa região armazena as instruções do programa.
Programação Básica com Linguagem C 34

Figura 3.5 Relação entre a pilha execução de programas C e o hardware.

Um depurador (em inglês: debugger) é um programa de computador


usado para testar outros programas e fazer sua depuração, que
consiste em encontrar os erros deste programa, caso exista.

O depurador GNU C permite interromper a execução do programa depurado em


qualquer ponto e examinar o conteúdo de suas variáveis. Em geral, os depuradores
também oferecem funcionalidades mais sofisticadas, como a execução passo a
passo do programa; a suspensão do programa para examinar seu estado atual, em
pontos predefinidos, chamados pontos de parada; o acompanhamento do valor de
variáveis.

A Linguagem C é mantida pela Free Software Foundation (FSF) e


distribuída pelo GNU Compiler Collection (GCC). Nos endereços abaixo,
pode–se obter as últimas versões do Compilador C:
1. http://tdm–gcc.tdragon.net/download
2. http://www.equation.com/servlet/equation.cmd?fa=fortran

A linguagem C evolui continuamente. A FSF e o GNU estão atentas às


necessidades tecnológicas dos nossos tempos.
Programação Básica com Linguagem C 35

4. Linguagem C

4.1. Visão Geral


A Linguagem C possui um conjunto de tokens11, descritos abaixo:

▪ palavras reservadas: palavras que pertençam à linguagem de programação


▪ identificadores: nomes compostos por letra (maiúscula ou minúscula), número e
sublinhado
▪ operadores relacionais: < > <=>= == !=
▪ operadores aritméticos: + * / – %
▪ operadores lógicos: && || & | !
▪ operador de atribuição: =
▪ delimitadores: ; , # espaço
▪ caracteres especiais: ( ) [ ] {} –> ponto
▪ funções da Biblioteca Padrão

Os identificadores são os nomes criados nos programas, pelo programador. As


regras básicas para a formação dos identificadores são:

1. o primeiro caractere deve ser sempre uma letra ou sublinhado


2. não são permitidos espaços
3. não pode ser palavra reservada
4. sensibilidade ao tipo de letra – letras maiúsculas e minúsculas em identificadores são
diferenciadas

Comentários de uma ou mais linhas nos em programas em C são encerrados


entre /* e */. Comentário de uma linha começa com // e termina no final da linha.
As palavras reservadas são: auto, break, case, char, const, continue, default, do,
double, else, enum, extern, float, for, goto, if, int, long, long, register, return, short,
signed, sizeof, static, switch, typedef, union, unsigned, void, volatile e while. E
também _Bool, _Imaginary, _Complex, inline e restrict.

11 Token ou componente léxico é uma cadeia de caracteres que tem um significado na linguagem de programação.
Programação Básica com Linguagem C 36

Macros São diretivas do pré–processamento que permitem substituir


porções de código antes da compilação. As instruções do pré–
processamento são seguidas do operador #, como #define e #include.

Exemplo 4.1 Um uso das macros é definir constantes, mostrada a seguir.


/* a macro #define permite o uso de constantes */
#define NomeDaConstante ValorDaContante // forma geral
#define PI 3.1415926535897932384626433 // π
#define DUZIA 12
#define NOME “Linguagem C”
#define LETRA ‘C’

4.1.1. A Função main


Os programas em C são organizados em funções. Eles possuem muitas funções,
em geral, organizadas em vários arquivos. Entretanto, um programa C deve possui
uma única função main, que determina o seu início.
O menor Programa C é:

Algoritmo 4.1 Menor Programa C

/* menor programa C */
int main( void ){
return 0;
}
Este programa tem a função main (obrigatória) que não recebe parâmetros
(indicado por void), retorna 0 (comando return) e não tem nem entrada/saída.

Programa Executável e o Sistema Operacional

Início – O Sistema Operacional (SO) carrega o programa executável na


memória principal e inicia seu processamento.
Fim – o comando return 0, da função main, encerra o programa
executável e devolve o controle ao SO. O valor 0 é uma mensagem ao
SO e significa execução encerrada sem erro.
4.1.2. Bloco de Comando
Associado às funções, e também a outros elementos da linguagem, tem–se o
Bloco de Comando, usado para organizar o código fonte (o texto que
escrevemos). Os blocos de comando agrupam um ou mais comandos.
Um bloco de comando começa com { e termina com }, são os delimitadores de
Programação Básica com Linguagem C 37

bloco. Os comandos de um bloco são executados em grupo, quantas vezes forem


necessárias. O fim de um comando dentro de um bloco é indicado por ponto e
vírgula (;), que são delimitadores de comando.
Pode haver um ou mais comandos dentro de um bloco, cada um destes
comandos devem ser encerrados por um ponto e vírgula. Pode–se criar blocos
vazios mas não tem uso prático.
Pode haver blocos dentro de blocos, e assim por diante. Nestes casos, além de
agrupar eles também podem isolar os comandos dentro de um bloco. Seus uso
requer prática e senso de organização.

identificador – nome criado pelo programador


comentário – /* */ e //
função – conjunto de comandos que realiza uma tarefa específica
main – função obrigatória, início do programa
bloco de comando – agrupa comandos encerrados por { e }
{ } – delimitador de bloco
; – delimitador de comando (ponto e vírgula)
Embora não seja recomendado, pode haver um ou mais comandos fora dos
blocos de comando, desde que necessário.

4.1.3. Estrutura Sequencial


É a estrutura de controle básica, em que os comandos em um programa são
executados um após o outro e na ordem em que são especificados. A estrutura
sequencial mais básica consiste de Entrada de Dados, Processamento e Saída de
Dados. O Algoritmo 4.1 apenas um comando na sua estrutura sequencial.
A Figura 4.1 é o paradigma “Entrada–Processamento–Saída”, um esquema
usado para ilustrar a resolução de problemas através de algoritmos.

Figura 4.1 Paradigma “Entrada–Processamento–Saída” como resolução de


problemas usando algoritmo.

A função é encerrada pelo comando return o, conforme mostrado no O Algoritmo


4.1. Há também as funções abort() e exit(n) que encerram Programas C. A função
exit(0) ou exit(EXIT_SUCCESS) informa o Sistema Operacional que o programa
terminou com sucesso. A função exit(1) ou exit(EXIT_FAILURE) informa o Sistema
Operacional que o programa terminou de maneira anormal, em geral com um ou
mais erros. O comando return 0 equivale ao exit(0), serve para zero ou outro valor.

4.1.4. Funções de Entrada/Saída (E/S)


A Linguagem C não possui meios para a entrada/saída de dados. Estes recursos,
e muitos outros, estão disponíveis na Biblioteca Padrão C.
Há várias funções para E/S à disposição do programador, as mais usada são
Programação Básica com Linguagem C 38

printf e scanf:

printf( "string de controle", lista de argumentos );


scanf (
"string de controle", lista de argumentos );

Figura 4.2 Relação entre E/S e as funções scanf/printf da Linguagem C.

stdin – constante para a entrada padrão (standard input), que é o


teclado.
stdout – constante para saída padrão (standard output), que é o
vídeo.

Exemplo 4.2 Programa simples para imprimir texto no vídeo (saída padrão –
stdout).
// macro para inclusão de recursos da Biblioteca Padrão
#include <stdio.h>
int main( void ){
printf( “Ola mundo!” );
return 0;
}

Este programa, ao ser compilado executado, escreve Ola mundo! no vídeo.


A saída padrão dos programas C é denominada stdout. Ela é associada ao vídeo,
por default12.

Na Tabela 4.1 estão listados os códigos para formatação das “strings de


controle” das funções printf e scanf.

Tabela 4.1 Códigos para formatação das “strings de controle” das funções printf e
scanf
Código Descrição
\\ barra invertida
\’ apóstrofo
\" aspas
\0 nulo ou NULL
\a sinal sonoro

12 Default – configurações pré estabelecidas; pode ser entendido como configurações originais ou “de fábrica”.
Programação Básica com Linguagem C 39

\b retrocesso
\f alimentação de formulário
\n nova linha
\N constante octal (N é um número octal)
\r retorno de carro
\t tabulação horizontal
\v tabulação vertical
\xN constante hexadecimal (N é um número hexadecimal)
Os tipos de dados de uma linguagem de programação são recursos valiosos para
programadores.

Exemplo 4.3 Programa para imprimir texto utilizando \n.


#include <stdio.h>
int main( void ){
printf( “Ola mundo!\nE um bom dia!” );
return 0;
}

Este programa escreve no vídeo:


Ola mundo!
E um bom dia!
O código \n em “Ola mundo!\nE um bom dia!” indica uma mudança de linha, tudo
que está antes dele numa linha e tudo que está depois dele em uma nova linha.
Observe que o \n não é impresso.
Assim funciona os demais controles, podendo haver tantos deles quantos forem
necessários.

O scanf será tratado junto com o tópico variáveis.

Erros a Evitar
Ao copiar a sentença printf( “Ola mundo!” ); para um editor de
texto, pode dar erro de compilação.
Causa: as aspas duplas do editor (“”) de texto não são iguais às que a
Linguagem C usa, que são (""). Logo, as aspas da sentença precisam
ser trocadas, assim: printf( "Ola mundo!" );
Note a diferença! Detalhes, detalhes, …, que, para nós humanos, são
insignificantes.
O mesmo se aplica às aspas simples.

4.2. Tipos de Dados


Os tipos de dados de uma linguagem de programação são recursos valiosos para
quem programa porque é por meio deles que são representados as quantidades do
mundo real, dos modelos e das ideias. As linguagens de programação implementam
formas de representar e manipular essas quantidades por meio de expressões.
Programação Básica com Linguagem C 40

tipo de dado define um conjunto de valores associado a um conjunto


de operações

A Linguagem C é rica em tipos de dados, e são organizados em tipos simples,


estruturados e ponteiro, Tabela 4.2. Note que há várias maneiras de organizar estes
tipos.

Tabela 4.2 Tipos de Dados da Linguagem C


Simples Estruturados Apontador
void string endereço
bool array
char struct
int union
float enum
double

Os tipos simples13 são:

• void – para indicar ausência de parâmetros e de retorno de valor (usado em


funções)
• bool – valor lógico14, para expressar as condições lógicas { false, true} ou {0,1}
• char – inteiro com sinal, símbolos da linguagem natural e tabela ASCII
• int – inteiro com sinal, faixa do conjunto dos números inteiros
• float – ponto flutuante com sinal, faixa do conjunto dos números reais com baixa
precisão
• double – ponto flutuante com sinal, faixa do conjunto dos números reais com alta
precisão

4.2.1. Modificadores de Tipo de Dado


A Linguagem C define quatro modificadores de tipo de dado, quais sejam:

13 Tipos simples ou primitivos pois podem ser combinados para criar tipos de dados estruturados.
14 A Biblioteca Padrão incluiu o arquivo #include<stdbool.h> para implementar o tipo lógico bool. Ao declarar bool x, é criada
a variável x do tipo lógico, que pode assumir valores true ou false.
Programação Básica com Linguagem C 41

1. signed – o tipo de dado possui sinal, é o padrão da linguagem


2. unsigned – o tipo de dado é positivo ou nulo
3. short – o tamanho do tipo de dado é reduzido à metade
4. long – o tamanho do tipo de dado é duplicado

Figura 4.3 Tipos de Dados da Linguagem C e seus modificadores.

4.2.2. Tipo void


O tipo void é usado em funções tanto para indicar ausência de parâmetros
quanto para indicar ausência de retorno de valor.
Notas:

• Os modificadores de tipo de dados não se aplicam ao tipo void


• O tipo void não possui operações matemáticas
• Ele não pode ser lido e nem escrito

4.2.3. Tipo char


O tipo char, embora seja elencado como inteiro porque, para a CPU, eles são
tratados como números inteiros. Para o conforto de quem programa e usuários
(humanos) eles podem ser visualizados na forma textual da linguagem natural além
da forma numérica da matemática. O tipo char é utilizado como número em alguns
programas de processamento de imagens.
Na Tabela 4.3 estão os tipos char e seus modificadores, o tamanho em bits e
bytes, faixa de variação e o formato de Entrada/Saída (E/S). Nesta tabela estão
incluídos os modificadores signed/unsigned. Os modificadores short/long não se
aplicam ao tipo char.

Tabela 4.3 Tipo char, tamanhos, faixas e formatos de E/S do tipo char e seus
modificadores
Tamanho Tamanho Faixa de Variação Formato
Tipo char
(b) (B) E/S
Programação Básica com Linguagem C 42

char 8 1 {–27, 27–1} %c


signed char 8 1 {–27, 27–1} %c
unsigned char 8 1 {0, 28–1} %hhu
Notas:

• Os tipos signed char e char são os mesmos tipos, o modificador signed é o default da
Linguagem C.
• Os modificadores short/long não se aplicam ao tipo char.
• O tipo char pode assumir valores inteiros com sinal na faixa {–128 a 256}.
• A Linguagem C pode tratar valores de tipos char como números ou como símbolos e,
dependendo dos valores, são os mesmos dos códigos ASCII.
• As operações matemáticas { + – * } são definidas para valores do tipo char podem
resultar em valores fora de sua faixa de variação, com resultados inesperados,
devendo ser usados como muito cuidado.
• Pode–se escrever valores de char utilizando as funções printf e scanf, os formatos
necessários estão na Tabela 4.3. O tipo char pode ser impresso como valores inteiros
(%d) ou como símbolos (%c).
• O computador utiliza os símbolos char para representar textos nos dispositivos de
saída mas, internamente, são tratados como números.

Seguem funcões para E/S de char:

• getc e getchar – abreviatura de get character, lê um byte de stdout; geralmente um


caractere ASCII.
• putc e putchar – abreviatura de put character, recebe um byte e exibe em stdin;
geralmente um caractere ASCII.

O tipo int não possui parte fracionária por isso são denominados de tipos de
ponto fixo.
Na Linguagem C, char é tratado como ponto fixo.

Pesquise na web: tipo char


Pesquise na web: getc e putc

4.2.4. Tipo int


O tipo int não possui parte fracionária por isso são denominados de tipos de
ponto fixo.

Na Tabela 4.4 estão os tipos int e seus modificadores, o tamanho em bits e


bytes e faixa de variação, e o formato de Entrada/Saída (E/S). Nesta tabela estão
incluídos os modificadores signed/unsigned e short/long.

Tabela 4.4 Tipo int, tamanhos, faixas e formatos de E/S do tipo int da Linguagem C
Programação Básica com Linguagem C 43

Tamanho Tamanho Faixa de Variação Formato


Tipo int
(b) (B) E/S
int 32 4 {–231,231–1} %d
unsigned int 32 4 {0,232–1} %u
short int 16 2 {–216,216–1} %hd
unsigned short int 16 2 {0,232–1} %hu
long int 64 8 {–263,263–1} %ld
unsigned long int 64 8 {0,264–1} %lu
Notas:

• Os tipos int são chamados tipos de ponto fixo (os tipos char também são ponto fixo
se tratados como inteiros).
• Os tipos signed int e int são os mesmos tipos, o modificador signed é o default da
Linguagem C.
• O tipo long int pode ser abreviado para long.
• O tipo int pode assumir valores inteiros com sinal na faixa {–2 31 a 264–1}.
• As operações matemáticas { + – * / % } são definidas para valores do tipo int.
• O transbordamento de dados em operações com valores destes tipos é pouco
comum, devido à sua grande faixa de variação – mas pode ocorrer.
• A subtração envolvendo valores de tipo unsigned int resultar em transbordamento de
dados, com resultados inesperados, devendo ser usados como muito cuidado.
• Como na matemática, não há divisão por zero, cabendo ao programador cuidar para
evitá–las.
• A divisão entre inteiros tem como resultado outro inteiro, a parte fracionária é
perdida.
• Pode–se escrever valores int utilizando as funções printf e scanf, os formatos
necessários estão na Tabela 4.4.
• O computador utiliza o tipo unsigned int e também unsigned long int para
representar grandezas positivas ou nulas, como endereços de memória.
• Estes tipos são muito úteis em Matemática Discreta, uma grande área da
Computação.
• A Biblioteca Padrão possui muitas funções exclusivas destes tipos, facilitando seu
uso.

A divisão inteira tem suas peculiaridades, leia com atenção o texto Divisão
Inteira, abaixo.

Divisão Inteira

São duas as divisões inteiras, cujos símbolos são {/ %}, com resultados
mostrado abaixo:
Programação Básica com Linguagem C 44

Sendo a e b inteiros, temos:


• a % b é também inteiro e igual ao resto da divisão entre a e b, indicado
por r
• a / b é também inteiro e igual ao quociente da divisão entre a e b,
indicado por q

Observe que, na divisão inteira, tanto r quanto q são inteiros. Se a = 5


e b = 2 então q = 2 e r = 1, ou seja, 5 / 2 = 2 e 5 % 2 = 1.

4.2.5. Tipos float e double


Na Tabela 4.5 estão os tipos float e double e seus modificadores, o tamanho em
bits e bytes e faixa de variação, e o formato de Entrada/Saída (E/S). Nesta tabela
está incluído apenas o modificador long.

Tabela 4.5 Tipo float e double, tamanhos, faixas e formatos de E/S do tipo int da
Linguagem C
Tamanho Tamanho Faixa de Variação Formato
Tipo
(b) (B) E/S
float 32 4 [±3.4E–38,±3.4E38] %f
double 64 8 [±1.7E–308,±1.7E308] %lf
long double 128 16 [±3.4E–4932,±3.4E4932] %Lf
Notas:

• Os tipos float, double e long double são chamados tipos ponto flutuante.
• Os tipos float, double e long double podem assumir uma grande faixa dos números
reais usados na Matemática.
• O tipo double é o default da Biblioteca Padrão e da Linguagem C.
• As operações matemáticas { + – * / } são definidas para valores destes tipos, e
também as funções matemáticas convencionais, como exponencial, trigonométricas,
potência e suas inversas.
• A operação { % } não é definida para estes tipos.
• O transbordamento de dados em operações com estes tipos é pouco comum, devido
à sua grande faixa de variação – mas pode ocorrer.
• Como na matemática, não há divisão por zero, cabendo ao programador cuidar para
evitá–las.
• A divisão entre tipos ponto flutuante tem como resultado outro tipos ponto flutuante,
o que inclui a parte fracionária.
• Pode–se escrever valores float e double utilizando as funções printf e scanf, os
formatos necessários estão na Tabela 4.5.
• O computador utiliza os tipos float, double e long double para cálculos de grande
precisão, notadamente em Cálculo Numérico, uma área com muitas aplicações.
• Em geral, os computadores realizam operações matemáticas por meio de
coprocessadores aritméticos, um dos componentes das modernas CPU’s.
• A Biblioteca Padrão possui muitas funções exclusivas destes tipos, facilitando seu
Programação Básica com Linguagem C 45

uso.

Os tipos float e double possuem parte fracionária e são denominados tipos de


de ponto flutuante. A diferença entre eles é a precisão, o número de dígitos
comportados por cada um deles.
As operações se comportam de acordo com o tipo. Por exemplo, a adição (+), a
subtração (–), a multiplicação (*) e a divisão (/) para variáveis dos tipos:

• char – a adição concatena variáveis char e não tem sentido subtrair, multiplicar e
dividir variáveis do tipo char se tratadas literalmente
• int e long int – a adição, subtração, multiplicação e divisão de variáveis int é como
se faz na matemática, mas a parte fracionária da divisão é perdida; os unsigned int e
unsigned long não assumem valores negativos, limitando as subtrações
• float e double – a adição, subtração, multiplicação e divisão destas variáveis é
como se faz na matemática com a precisão inerente a cada tipo
• int, long int, float e double – as operações permitidas com estes tipos não
possuem a precisão da matemática, todos eles têm limites inferiores e superiores
que limitam estas operações; por exemplo, não existe dízima periódica em
programas C porque mesmo os pontos flutuantes têm sua a parte fracionária
limitada pela precisão da máquina

O arquivo limits.h, da Biblioteca Padrão, contem constantes para os valores


limites dos tipos da Linguagem C.

Pesquise na wikipédia: math.h

4.2.6. Estrutura dos Tipos Simples

A Figura 4.4 mostra a estrutura dos tipos da Linguagem C em escala, nela pode–
se observar a estrutura interna dos tipos char e int (com e sem bit de sinal, short,
unsigned e long) e também dos tipos float e double (com bit de sinal, expoente e
fração). O tipo long double não foi apresentado por ser muito grande.
Nesta figura, o tamanho dos tipos são dados em octetos, com a cor amarela
representa o bit de sinal, a cinza indica número inteiro, o azul refere–se ao
expoente e o verde à fração dos pontos flutuantes.
O sinal tem sempre o mesmo tamanho (1 bit), em que 0 representa o sinal
positivo e 1 o sinal negativo. O tamanho do expoente e da fração varia entre os
tipos float e double, devido à precisão numérica dos mesmos.
Em geral, float são de 7 dígitos, double de 15 dígitos e long double de 19 dígitos
de precisão. A precisão dos tipos ponto flutuante depende do compilador. O tipo
ponto flutuante (float, double e long double) são padrões internacionais,
regulamentados pelo IEEE 754–1985.
Programação Básica com Linguagem C 46

Figura 4.4 Tipos simples da Linguagem C com seus octetos e as cores indicando: a)
amarelo - bit de sinal, b) cinza - número inteiro, c) azul - expoente e d) verde –
fração

A Figura 4.4 mostra a diversidade de tipos da Linguagem C e também que é


necessário muita entendimento para seu uso, leitura e gravação. Os tipos que
possuem mesmo tamanho diferem quanto ao sinal ou estrutura, se possuem sinal
tem tamanhos ou estruturas diferentes.
Leia com atenção o texto Erros a Evitar, abaixo.

Erros a Evitar

Ocorre overflow quando uma operação resulta em valores maiores


do que o da faixa de variação dos dados
Ocorre underflow quando uma operação resulta em valores
menores do que o da faixa de variação dos dados
Em Português, o termo transbordamentos de dados refere–se
tanto ao overflow quanto ao underflow
A Linguagem C não verifica automaticamente o transbordamento de
dados, cabe ao programador evitar a ocorrência de anomalias em
programas C
Checagem de limites pode prevenir transbordamentos de dados
A Linguagem C não verifica automaticamente se o divisor é zero, é
tarefa do programador evitar toda e qualquer divisão por zero
A Exemplo 4.4 imprime o tamanho em bytes dos tipos da Linguagem C. Os
valores dos tipos int podem variar entre as arquiteturas.

Exemplo 4.4 Programa C para escrever o tamanho dos tipos em bytes.


#include <stdio.h>
#include <stdbool.h>
int main(void){
printf( "\n char = %d B", sizeof( char ) );
printf( "\n bool = %d B", sizeof( bool ) );
Programação Básica com Linguagem C 47

printf( "\n int = %d B", sizeof( int ) );


printf( "\n short = %d B", sizeof( short ) );
printf( "\n long = %d B", sizeof( long ) );
printf( "\n long long = %d B", sizeof( long long ) );
printf( "\n unsigned char = %d B", sizeof( unsigned char ));
printf( "\n unsigned int = %d B", sizeof( unsigned int ));
printf( "\n unsigned short= %d B", sizeof( unsigned short ));
printf( "\n unsigned long = %d B", sizeof( unsigned long ));
printf( "\n float = %d B", sizeof( float ) );
printf( "\n double = %d B", sizeof( double ) );
printf( "\n long double = %d B", sizeof( long double ) );
return 0;
}
A função sizeof retorna um int, portanto o formato usado é %d.

A Exemplo 4.5 imprime os limites de alguns tipos da Linguagem C.

Exemplo 4.5 Programa C para imprimir limites de tipos da Linguagem C.

#include <stdio.h>
int main(void){

#include <limits.h>

printf( "\n char min = %d" , SCHAR_MIN );


printf( "\n char max = %d" , SCHAR_MAX );

printf( "\n int min = %d" , INT_MIN );


printf( "\n int max = %d" , INT_MAX );

printf( "\n long int min = %ld" , LONG_MIN );


printf( "\n long int max = %ld" , LONG_MAX );

#include <float.h>

printf( "\n float min = %e" , FLT_MIN );


printf( "\n float max = %e" , FLT_MAX );

printf( "\n double min = %le", DBL_MIN );


printf( "\n double max = %le", DBL_MAX );

printf( "\n long double min = %Le", LDBL_MIN );


printf( "\n long double max = %Le", LDBL_MAX );
Programação Básica com Linguagem C 48

printf( "\n epsilon float = %e" , FLT_EPSILON );


printf( "\n epsilon double = %le", DBL_EPSILON );
printf( "\n epsilon long double = %Le", LDBL_EPSILON );

return 0;
}
Observe os formatos usados para cada um dos tipos (%e é formato para notação
científica).

Domínio (D) x Operações (O): Tipos de Dados

char – D: Caracteres ASCII; O: código ASCII e literais


int – D: Números Inteiros; O: {+ – * / }, Matemática Discreta
float, double – D: Números Reais; O: {+ – * / }, Cálculo Numérico

Cada tipo de dados tem suas regras próprias, seus limites, suas
aplicações e, sobretudo, seu formato de E/S – é necessário
compreendê-los muito bem.
A Biblioteca Padrão possui muitas funções para cada tipo de dados,
fornecendo ferramentas úteis para a programação.

4.2.7. Tipos Estruturados


Os dados estruturados (string, array, struct, union e enum) são agrupamentos
de tipos simples e são estudados em capítulos específicos.

4.2.8. Tipos Apontador


Os apontadores são tipos para representar endereços de memória e itens de
hardware. É um dos grandes diferencias da Linguagem C.

Pesquise na wikipédia: math.h


Programação Básica com Linguagem C 49

Pesquise na web: tipos da linguagem


Pesquise na web: especificação de formato

4.2.9. Exercícios

1. Os números de telefone no Brasil são de 9 dígitos, sendo que o primeiro é


necessariamente um 9. Quantos números de telefone são possíveis no Brasil? Qual
tipo C deve ser usado para armazenar estes números de telefone?

2. O endereço IPv4 de um dispositivo na Internet é um número de 4 bytes, do tipo


192.168.255.255. Qual o número de endereços IPv4 possíveis? Qual tipo C deve ser
usado para armazenar endereços IPv4?

3. Interfaces de rede recebem uma identificação do fabricante conhecida como


endereço MAC que é um número de 48 bits. Quantas interfaces de rede podem ser
dadas a cada habitante do planeta? Qual tipo C deve ser usado para armazenar
endereços MAC?

4. O endereçamento IPv6 de um dispositivo na Internet é de 128 bits. Quantos


número de endereços IPv6 podem ser dados a cada metro quadrado da superfície do
planeta? Qual tipo C deve ser usado para armazenar endereços IPv6?

5. No calendário Gregoriano, uma data é uma sequência de 8 dígitos da forma


d1d2m1m2a1a2a3a4, onde d1 d2, m1 m2 e a1 a2 a3 a4 são dígitos representando o dia, mês
e ano, respectivamente. Por exemplo, 25122012 e 14071889 são datas e 31022013
e 48151623 não são. Desconsiderando os anos bissextos, quantas das sequências de
8 dígitos são datas válidas? Quantas dela já ocorreram? Qual tipo C deve ser usado
para armazenar endereços de data?

6. Um certo monitor de computador tem resolução de 1920x1080 pixels com


resolução de cor de 32 bits (isto é, cada pixel pode assumir 2 32 cores diferentes). Sua
frequência de varredura (isto é, a frequência com que a imagem exibida pode ser
exibida) é de 60 Hz. Quanto tempo, no mínimo, levaria o monitor para exibir todas as
imagens possíveis? Quantos pixels este monitor exibe por segundo?

4.3. Constantes

Constante – armazena valor que não podem ser modificadas durante


a execução de um programa
Programação Básica com Linguagem C 50

Notas:

• Diretivas de preprocessamento são iniciadas pelo símbolo #


• Uma constante precisa ser declarada, pode–se usar a diretiva #define
• Diretivas do preprocessamento permitem substituir porções de código antes da
compilação
• É costume o nome das constantes usarem apenas letras maiúsculas

Além do uso de macro pode–se usar a palavra reservada const para declarar
constantes.
A sintaxe15 para declarações uma constante em C é:

const <tipo de dado da constante> <nome da constante> = <valor da


constante>;

Esta forma de declaração tem 6 partes obrigatórias.

Exemplo 4.6 Declaração de constantes em programa C.

#include <stdio.h>

#define PI 3.141592
#define LETRA ‘A’
const float RAIO = 2.172;
const int MIN = 0, MAX = 0;
const double SALARIO = 30000.00;

int main(void){
const int DUZIA = 12;
printf( "\n PI = %lf”, PI );
printf( "\n LETRA = %c” , LETRA ); // LETRA é tratada como
símbolo
printf( "\n LETRA = %d” , LETRA ); // LETRA é tratada como
número int
printf( "\n RAIO = %f” , RAIO );
printf( "\n MIN = %d” , MIN );
printf( "\n MAX = %d” , MAX );
printf( "\n SALARIO = %lf”, SALARIO );
printf( "\n DUZIA = %d” , DUZIA );
return 0;
}
MIN e MAX foram declaradas juntas, separadas por vírgula.
A vírgula é o separador de elementos de uma lista.
A constante DUZIA é dita local à função main e as demais são ditas globais do

15 Na computação, aquilo que está entre < > é obrigatório.


Programação Básica com Linguagem C 51

programa.
PI e LETRA estam declaradas usando macro e as demais usam declaração const.
A macro não requer ponto e vírgula (e se usar dá erro de compilação).
A declaração const requer ponto e vírgula no final (e se não usar dá erro de
compilação).
Observe os formatos usados para imprimir cada uma das constantes. A constante
do tipo char pode ser impressa como símbolo ou como número, só depende do
formato usado.
São detalhes importantes que, para nós humanos, são insignificantes.

4.4. Variáveis
Conforme pode ser visto na Figura 1.1, os dados utilizados pelo computador são
armazenados locais da sua memória de trabalho. Dar nome a estes locais da
memória permite gerenciar o processamento de dados no computador.
Os locais não mudam mas os valores neles armazenados mudam conforme a
necessidade, ou seja, os valores variam. O conceito de variáveis está relacionado
aos locais da memória principal onde valores são armazenados.
Variável são instâncias armazenadas na memória cujos valores são utilizados
durante a execução de um programa.

variável – variável é uma região reservado na memória para


armazenar valores de um tipo de dado

Nota:

• toda a variável tem um tipo de dado, o programador precisa escolher um tipo de


dados para ela
• o tipo de dado da variável determina o que ela é capaz de armazenar
• o tipo de dado da variável determina quais operações pode–se fazer com ela
• toda variável tem um identificador, o programador precisa criar um nome para ela
• o computador reserva um local na memória para armazenar cada variável de acordo
com seu tipo de dado
• variáveis podem ter um valor inicial atribuído a ela
• variáveis que não possuem valor diz–se que tem “lixo de memória”
• tecnicamente, declarar uma variável é alocar memória de máquina para seu tipo e
definir as operações desta variável e, opcionalmente, atribuir um valor à memória
alocada

A memória de um computador é um mapa de bits como ilustra a Figura 1.3. O


Computador associa o nome de uma variável a uma região da sua memória RAM,
na qual para armazena o valor desta variável, que pode ser modificado pelo
Programação Básica com Linguagem C 52

programa, Figura 4.5. Cada variável declarada tem sua própria região demarcada
na memória do computador – tecnicamente seu endereço de memória.

Figura 4.5 Esquema da associação entre nome de variável de tipo char e a sua
região da memória do computador.

O tamanho do endereço na memória de uma variável depende do seu tipo. Por


simplicidade, a Figura 4.5 mostra o esquema da variável ch do tipo char, que
possui um endereço de 8 bits, após sua declaração.

Variáveis possuem nome, estrutura e conteúdo. A estrutura é


estabelecida pelo tipo de dado que a variável armazena (Figura 4.4), é
a região da memória reservada para a variável. O conteúdo é o valor
armazenado na variável conforme seu tipo de dado (Tabela 4.3, Tabela
4.4 ou Tabela 4.5).

4.4.1. Declaração
A sintaxe16 de declaração de uma variável em C é:

<tipo da dado variável> <nome da variável> [= <valor inicial da


variável>];
Esta declaração tem partes obrigatórias e partes opcionais.
Exemplo 4.7 Declaração de variáveis em programa C e sua impressão.

#include <stdio.h>
int main(void){
char c1, c2 = ‘A’, c3 = 65;
int i1, i2 = 3;
float f1, f2 = 4.0;
double d1, d2 = 5.0;
// imprimindo valores
printf( "\n c1 = %c” , c1 ); // sem valor inicial, impressão do
“lixo da memória”
printf( "\n c2 = %c” , c2 );
printf( "\n c2 = %d” , c2 );
printf( "\n c3 = %c” , c3 );

printf( "\n i1 = %d” , i1 ); // sem valor inicial, impressão do


16 Na computação, aquilo que está entre [ ] é opcional.
Programação Básica com Linguagem C 53

“lixo da memória”
printf( "\n i2 = %d” , i2 );

printf( "\n f1 = %f” , f1 ); // sem valor inicial, impressão do


“lixo da memória”
printf( "\n f2 = %f” , f2 );

printf( "\n d1 = %lf”, d1 ); // sem valor inicial, impressão do


“lixo da memória”
printf( "\n d2 = %lf”, d2 );

return 0;
}
As variáveis c2 e a3 possuem o mesmo valor pois, em ASCII, ‘A’ é o decimal 65.
Todas as variáveis são ditas locais à função main. Este programa não tem variável
global.
Foram declaradas duas variáveis de cada tipo de dado, uma sem valor inicial e a
outra com valor inicial. Veja que o tipo char permite valores iniciais da tabela
ASCII, podendo ser seus valores simbólico ou decimal. Vale lembrar que ‘A’ e o
decimal 65 em ASCII.
Variável que cujo valor é o chamado lixo de memória é de pouca ou nenhuma
utilidade uma vez que não pode produzir resultado confiável.
Observe os formatos usados para cada imprimir cada uma das variáveis. Variáveis
do tipo char pode ter valor inteiro ou literal e impressas como símbolo ou como
número, só depende do formato usado.
São detalhes importantes que, para nós humanos, são insignificantes.

O Sistema Operacional carrega os programas executáveis para a


memória principal e aloca memória para cada uma de suas variáveis,
dessa forma, cada variável passa a possuir um endereço de memória,
além do seu nome, estrutura e conteúdo.
A Linguagem C possui um tipo específico para armazenar e operar
endereços de memória. São os apontadores, a serem estudados em
outro capítulo deste livro.

4.4.2. Leitura e Escrita de Variáveis


A Biblioteca Padrão fornece as funcionalidades de E/S para a Linguagem C. Os
podem ser lidos e escritos com pritnf e scanf, respectivamente. Na Tabela 4.6 estão
os comandos para leitura e escrita dos tipos char, int, float e double.

Tabela 4.6 Comando para leitura e escrita dos tipos simples


Variável Escrita Leitura
Programação Básica com Linguagem C 54

bool x printf( "%d" , x ) printf( "%d" , &x )


char x printf( "%c" , x ) scanf( "%c" , &x )
unsigned char x printf( "%hhu", x ) scanf( "%hhu", &x )
short int x printf( "%hd" , x ) printf( "%hd", &x )
unsigned short int x printf( "%hu" , x ) printf( "%hu", &x )
int x printf( "%d" , x ) printf( "%d" , &x )
unsigned int x printf( "%u" , x ) printf( "%u" , &x )
long int x printf( "%ld" , x ) printf( "%ld", &x )
unsigned long int x printf( "%lu" , x ) printf( "%lu", &x )
float x printf( "%f" , x ) scanf( "%f" , &x )
double x printf( "%lf" , x ) scanf( "%lf" , &x )
long double x printf( "%Lf" , x ) scanf( "%Lf" , &x )
Notas:

• é necessário o caractere & antes das variáveis no scanf


• se a entrada padrão for o teclado, ao executar um printf, o computador aguarda a
digitação do valor da variável até que se tecle ENTER.
• a tecla ENTER finaliza a leitura pelo teclado
• é comum errar o formato de entrada dos tipos de dados, uma maneira de certificar–
se é a impressão dos dados lidos.

Tanto o printf quanto o scanf escreve/lê mais de uma variável. A Figura 4.6
mostra o formato do printf que escreve o valor da hora. Este mesmo conceito se
aplica ao scanf.

Figura 4.6 Uso do printf para escrever os valores de três variáveis.

Erros a Evitar

Como visto na Figura 4.4, os tipos da Linguagem C são muito


diferentes uns dos outros. Quando não diferem no tamanho, diferem
no sinal ou na estrutura interna (Figura 4.4).
A função scanf é muito exigente, faz a leitura correta do valor da
variável apenas se o formato corresponder exatamente ao tipo da
variável. Caso contrário, em geral, ele atribui zero ao valor lido.

Uma boa prática de programação é escrever os valores das variáveis


lidas pelos scanf. Principalmente para programadores iniciantes. É
muito comum o erro de formato de E/S.

Os exemplos abaixo, ilustram os comandos de leitura/escrita dos tipos char, int,


float e double.
Programação Básica com Linguagem C 55

Exemplo 4.8 Lendo char do teclado e escrevendo–a na tela


#include <stdio.h>
int main ( void ){
char c;
printf("Digite uma letra: " );
scanf("%c", &c );
printf("Letra digitada: %c", c );
return 0;
}
Ao executar este programa, digite o caractere e tecle ENTER.
Se for digitado mais de um caractere será lido apenas o primeiro, os demais serão
desprezados.
É necessário o caractere de controle & para leitura dos tipos simples.

Exemplo 4.9 Lendo inteiros, separados por espaço, do teclado e escrevendo–a na


tela
#include <stdio.h>
int main ( void ){
int x, y;
printf("Digite os valores de x e y : " );
scanf("%d %d", &x, &y );
printf(" x = %d", x );
printf(" y = %d", y );
return 0;
}
Ao executar este programa, digite dois números inteiros separados por espaço e
tecle ENTER.

Exemplo 4.10 Lendo inteiros, separados por vírgula, do teclado e escrevendo–a na


tela
#include <stdio.h>
int main ( void ){
int x, y;
printf("Digite os valores de x e y : " );
scanf("%d,%d", &x, &y );
printf(" x = %d", x );
printf(" y = %d", y );
return 0;
}
Programação Básica com Linguagem C 56

Ao executar este programa, digite dois números inteiros separados por vírgula e
tecle ENTER.

Exemplo 4.11 Lendo float do teclado e escrevendo–a na tela


#include <stdio.h>
int main ( void ){
float x;
printf("Digite o valor de x : " );
scanf("%f", &x );
printf(" x = %f", x );
return 0;
}

Exemplo 4.12 Lendo double do teclado e escrevendo–a na tela


#include <stdio.h>
int main ( void ){
double x;
printf("Digite o valor de x : " );
scanf("%lf", &x );
printf(" x = %lf", x );
return 0;
}

Exemplo 4.13 Programa C para leitura dos valores de variáveis do tipos simples e
seus modificadores. O programa foi organizado em quatro funções, para facilitar o
seu entendimento, a função main chama as demais.
#include <stdio.h>
void Bool( void ){
bool b;
printf( "\n" );
printf( "De um valor bool {0,1}:" );
scanf ( "%d" , &b );
printf( "Valor lido: %d" , b );
}

void Char( void ){


char c;
unsigned char uc;
Programação Básica com Linguagem C 57

printf( "\n" );
printf( "De um valor char:" );
scanf ( "%c" , &c );
printf( "Valor lido: %c" , c );

printf( "\n" );
printf( "De um valor unsigned char:" );
scanf ( "%hhu" , &uc );
printf( "Valor lido: %hhu" , uc );
}
void Int( void ){
int i;
unsigned int ui;
short int si;
unsigned short int usi;
long int li;
unsigned long int uli;

printf( "\n" );
printf( "De um valor int:" );
scanf ( "%d" , &i );
printf( "Valor lido: %d" , i );

printf( "\n" );
printf( "De um valor unsigned int:" );
scanf ( "%u" , &ui );
printf( "Valor lido: %u" , ui );

printf( "\n" );
printf( "De um valor short int:" );
scanf ( "%hd" , &si );
printf( "Valor lido: %hd" , si );

printf( "\n" );
printf( "De um valor unsigned short int:" );
scanf ( "%hu" , &usi );
printf( "Valor lido: %hu" , usi );

printf( "\n" );
printf( "De um valor long int:" );
scanf ( "%ld" , &li );
Programação Básica com Linguagem C 58

printf( "Valor lido: %ld" , li );

printf( "\n" );
printf( "De um valor unsigned long int:" );
scanf ( "%lu" , &uli );
printf( "Valor lido: %lu" , uli );
}

void Float( void ){


float f;
double d;
long double ld;

printf( "\n" );
printf( "De um valor float:" );
scanf ( "%f" , &f );
printf( "Valor lido: %f" , f );

printf( "\n" );
printf( "De um valor double:" );
scanf ( "%lf" , &d );
printf( "Valor lido: %lf" , d );

printf( "\n" );
printf( "De um valor long double:" );
scanf ( "%Lf" , &ld );
printf( "Valor lido: %Lf" , ld );
}
int main( void ){
Bool();
Char();
Int();
Float();
return 0;
}
Nas funções, exceto main, são declaradas uma variável de cada tipo e seus
modificadores, em seguida é feita a leitura de stdin e escrita em stdout. Estes
exemplos servem de modelos para outros programas com E/S.
Programação Básica com Linguagem C 59

Lendo e escrevendo textos

Enquanto o tipo char é capaz de conter um único carácter, a Linguagem C


possui o tipo string que pode conter vários carácteres, como frases e
textos diversos.

O tipo string será visto em um capítulo específico, com mais detalhes.

A declaração de uma string é feita usando o tipo char, o tamanho máximo


do texto armazenado. A Linguagem C marca o fim da string com o caractere
NULL (ASCII 0000 0000).

O formato de leitura e escrita do tipo string é %s.

Sintaxe para declarar uma string de nome str e tamanho 25 e valor inicial
“valor inicial de str”:

char str[26] = “valor inicial de str”; // 26 = 25 +1 (nome+NULL)


#include <stdio.h>
int main( void ){
char nome[35] = "Nome padrao",
profissao[35] = "Profissao padrao";

printf( "Digite o nome: " );


scanf ( "%s", nome );
printf( "Digite ao profissao: " );
scanf ( "%s", profissao );

printf( "\n Nome : %s ", nome );


printf( "\n Profissao: %s ", profissao );
return 0;
}
Note que o formato de leitura e escrita do tipo string são iguais.

4.4.3. Escopo de Variáveis


O escopo de uma variável determina a sua visibilidade (capacidade de uso), ou
seja, onde uma variável pode ser utilizada como um identificador em um programa.
Quanto ao escopo, as variáveis de um programa podem ser classificadas em
variável local, variável global ou parâmetro formal, Tabela 4.7.

Tabela 4.7 Escopo de variáveis C


Escopo Visibilidade
• São aquelas variáveis declaradas dentro do bloco de uma função
• São visíveis apenas na função onde foi declarada
Variável
• Não podem ser usada ou modificadas por outras funções
Local
• Existem enquanto a função onde foi declarada estiver sendo
executada
Programação Básica com Linguagem C 60

Parâmetro
• São variáveis locais da função
Formal
• São variáveis declaradas fora dos blocos das funções
Variável • São acessíveis a todo programa a partir do ponto em que foi
Global declarada, podendo ser usadas e modificadas a partir daí
• Existem durante toda a execução do programa

• Se uma variável local de uma função tiver o mesmo nome de uma


variável global, dentro da função prevalece a variável da função
Nomes • Generalizando, variáveis locais prevalecem sobre as demais
variáveis com mesmo nome
• O compilador C não permite conflito de nomes

Exemplo 4.14 Escopo de variáveis em programas C


#include <stdio.h>

// declaração de variáveis globais – visíveis em f1, f2 e main

void f1( parâmetros formais ){ // parâmetros são locais


// declaração de variáveis locais da função f1
// visíveis apenas nesta função e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco e nos blocos internos
}
}
}

// declaração de variáveis globais – visíveis em f2 e main

void f2( parâmetros formais ){ // parâmetros são locais


// declaração de variáveis locais da função f2
// visíveis apenas nesta função e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco
Programação Básica com Linguagem C 61

}
}
}

// declaração de variáveis globais – visíveis em main

int main( void ){


// declaração de variáveis locais da função main
// visíveis apenas nesta função e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco e nos blocos internos
{
// declaração de variáveis locais deste bloco
// visíveis apenas neste bloco e nos blocos internos
}
}
return 0;
}
// declaração de variáveis globais – sem utilidade prática

4.4.4. Classe de Armazenamento de Variáveis


A classe de armazenamento ou modificadores de armazenamento de uma
variável determina onde ela é armazenada.
As classes de armazenamento em C são representadas pelas palavras
reservadas auto, const, static, extern e register.

Tabela 4.8 Classe de armazenamento de variáveis C


Classe Armazenamento
a)local para a função onde está definida
b)a palavra reservada auto é sempre opcional, e raramente utilizada
auto
c)é a classe default
d)existe enquanto a função onde foi declarada estiver sendo executada

e) utilizada para declarar constantes


const f) não podem ter o seu valor alterado

static g)local para a função onde está definida


h)retém seu valor entre chamadas da função
i) existe durante toda a execução do programa
extern j) está definida fora de qualquer função
k)está disponível globalmente para todas as funções localizadas abaixo da
Programação Básica com Linguagem C 62

declaração da variável
l) foi declarada em outro arquivo.

m) será armazenada em local com maior velocidade de acesso, se


register
possível em um registrador da CPU e não na memória RAM.

4.5. Expressões
O propósito de uma expressão é especificar um valor a ser calculado.

expressão – combinação de constantes, variáveis, operadores e


chamadas de funções que, após avaliadas de acordo com as regras de
precedência e de associatividade, resulta um valor

A Linguagem Expressão C possui expressões aritméticas e lógicas. Antes de


discutir sobre elas, é necessário apresentar os seus operadores.

operador – símbolo que representa uma operação da matemática ou


da lógica

4.5.1. Operadores Aritméticos e Lógicos


Os operadores da linguagem C é o conjunto de símbolos que representa as
operações básicas da matemática e da lógica, a saber:

Tabela 4.9 Operadores Aritméticos da Linguagem C


Operador Ação Exemplo
– menos unário a = –b
+ mais unário a = +b
++ incremento ++a, a++
–– decremento ––a, a––
* multiplicação a=b*c
/ divisão inteira a=b/c
/ divisão real a=b/c
% resto da divisão inteira a=b%c
+ soma a=b+c
– subtração a=b–c
Programação Básica com Linguagem C 63

Erros a Evitar ao usar o Operador /

O operador / é usando para duas operações de divisão.


A divisão inteira, envolvendo variáveis do tipo int, resulta em um valor
do tipo int e, portanto, não possui parte fracionária.
A divisão real, envolvendo variáveis do tipo float ou double, resulta
em um valor do tipo float ou double e, portanto, possui parte
fracionária.
Como são resultados de tipos diferentes, requerem formatos de
impressão diferentes.

Tabela 4.10 Operadores Lógicos da Linguagem C


Operador Ação Exemplo
! negação lógica !a
> maior que a>b
>= maior ou igual a a >= b
< menor que a<b
<= menor ou igual a a <= b
== igual a a == b
!= diferente de a != b
&& and a && b
|| or a || b

Tabela 4.11 Operadores de Atribuição da Linguagem C


Operador Ação Exemplo
= atribuição a=b
op= atribuição abreviada a op= b (a= a op b)

Erros a Evitar ao usar Operador = e ==

Os operadores = e == podem ser trocados em expressões lógicas.


É comum usar = em lugar de ==.
Infelizmente, o compilador não identifica estes erros.

Tabela 4.12 Outros Operadores da Linguagem C


Operador Ação Exemplo
() parêntesis a = b*(c+d)
sizeof função a = sizeof(int)
, vírgula separador de lista
O ponto e vírgula (;) não é operador, ele é o delimitador de comando. Ele não faz
parte de expressões e, sim, indica seu fim.
Há outros operadores na Linguagem C, que serão vistos a seu tempo.
Programação Básica com Linguagem C 64

4.5.2. Precedência e Associatividade de Operadores


A precedência dos operadores estabelece regras para avaliação de expressões
quando nelas há mais de um operador. A Tabela 4.13 lista os operadores em ordem
decrescente de precedência.
Alguns operadores possuem mesma precedência, como é o caso de {+ –},
sendo necessário estabelecer a associatividade entre eles, que é dada pela direção
de ocorrência na expressão. A Tabela 4.13 indica esta direção como "da esquerda
para a direita" (e–d) e "da direita para a esquerda" (d–e).
No caso de uma expressão com {+ –}, que tem direção é e–d, a subtração é
efetuada antes da adição.

Tabela 4.13 Precedência e Associatividade dos Operadores da Linguagem C


Precedência (Maior) Associação*
()
! ++ –– – * sizeof d–e
*/% e–d
+– e–d
< <= > >= e–d
== != e–d
&&
||
= += –= *= /= d–e
,
Menor
* e–d: da esquerda para a direita; d–e: "da direita para a esquerda"

4.5.3. Expressões Lógicas


As expressões lógicas dão resultado verdadeiro ou falso.
São compostas por operadores relacionais (> >= < <=), operadores lógicos (&&
|| == !=). Podem ainda conter expressões aritméticas.
A linguagem C expressa suas condições lógicas em falso (0) e verdadeiro
(diferente de 0, representado por 1).
A Tabela 4.14 mostra exemplos de expressões lógicas em matemática, em C e
seus correspondes valores e condições lógicas.

Tabela 4.14 Exemplos de expressões lógicas em matemática, em C e seus


correspondes valores lógicos
Expressão Lógica Expressão Lógica Valores de x, y, Valor Lógico Valor Numérico
em C z em C em C
x ≥ 10 x >= 10 x=9 false 0
x > 10 e y < 20 (x > 10) && (x < 20) x = 11, y = 15 true 1
x+y=5 ( x + y ) == 5 x = 1, y = 5 false 0
x+y≠5 ( x + y ) != 5 x = 1, y = 5 true 1
x > 10 ou y < 20 (x > 10) || (x < 20) x = 11, y = 15 true 1
Programação Básica com Linguagem C 65

false – valor nulo ou expressão que resulte nulo


true – valor não nulo ou expressão que resulte não nulo

A linguagem C expressa suas condições lógicas em falso (0) e verdadeiro


(diferente de 0, representado por 1).

Pesquise na web: expressões lógicas para programação

Tabela verdade é usado em lógica para determinar o valor lógico de uma


expressão, Tabela 4.15 apresenta os resultados das tabelas verdade &&, || e suas
negações.

Tabela 4.15 Tabela verdade &&, || e suas negações


A B A && B A || B !(A && B) !(A || B) !A !B
V V V V F F F F
V F F V V F F V
F V F V V F V F
F F F F V V V V

Exemplo 4.15 Qual expressão lógica para verificar:


a) uma pessoa é de maior: idade > 18 :: no Brasil
b) uma pessoa é obrigada a votar: (idade >= 18) && (idade <= 70) :: no Brasil
c) condição de existência de raiz quadrada real: x >= 0, x é float
d) condição de existência de logaritmo: x > 0, x é float
e) x é um número par: (x % 2) == 0, x é int
f) x é um número ímpar: (x % 2) != 0, x é int
g) cálculo da média de valores: n > 0, n é int e n é o contador de parcelas

Exemplo 4.16 Qual expressão lógica para x nos intervalos:


a) [a,b] – a ≤ x ≤ b – fechado tanto à esquerda quanto à direita: (a <= x) && (x <=
b)
b) (a,b] – a < x ≤ b – aberto à esquerda e fechado à direita: (a < x) && (x <= b)
b) [a,b) – a ≤ x < b – fechado à esquerda e aberto à direita: (a <= x) && (x < b)
c) (a,b) – a < x < b – aberto tanto à esquerda quanto à direita: (a < x) && (x < b)

Exemplo 4.17 Qual o significado da expressão lógica:


Programação Básica com Linguagem C 66

a) (x <= a) || (x >= b) – o valor lógico de x ∊ (a,b) é FALSO


b) (x < a ) || (x >= b) – o valor lógico de x ∊ [a,b) é FALSO

Exercício 4.1 A figura abaixo possui 10 (10) regiões. Denominadas R1, R2, …, R10.
Considere que R10 contém todas as outras regiões. Escreva expressões lógicas
para representar as sentenças abaixo:

1. R1
2. R10 + R1
3. R1 + R2 – R4
4. R2 + R3 + R4 + R5

Pesquise na web: tabela verdade para programação

4.5.4. Expressões Aritméticas


As expressões aritméticas envolvem operadores de adição (+), subtração (–),
multiplicação (*), divisão (/) e módulo (%). Estes símbolos (+ – * / %) são
denominados operadores aritméticos.
Como na matemática, há uma ordem de prioridade na avaliação dos operadores
numa expressão aritmética, chamada de precedência de operadores para a
avaliação de expressões aritméticas nos programas de computador.
Na linguagem C, a precedência é primeiro para os parênteses, seguido da
multiplicação, divisão, %, adição e subtração.

Exemplo 4.18 Expressões aritméticas em C:


Expressão Matemática Correspondência em Linguagem C
c=a+b c = a + b;
d=c×(a+b) d = c*(a+b);
Programação Básica com Linguagem C 67

a d = (a/b)*c;
d= ×c
b
a c e = a/b + c/d;
e= +
b d
a e = (a/b – c)/d;
−c
b
e=
d
a mod b−c e = (a % b – c)/d;
e=
d
É uma boa prática testar expressões aritméticas para verificar se foram codificadas
corretamente.

Exemplo 4.19 Expressões aritméticas em C:


Expressão Matemática Correspondência em Linguagem C
b
c=a c = pow(a,b)
d= √(a+b) d = sqrt(a+b)
2 2
b=cos(a) + sen(a) b = pow(cos(a),2.0)+pow(sin(a),2.0)
f=
√cos (a)+ sen(b) f = sqrt( cos(a) + sin(b) ) / ( exp(c) – log(d) )
ec −ln(d)
b = abs(a); // b, a int
b=|a|
b = fabs(a); // b, a float
É necessário #include <math.h> para usar abs, exp, fabs, log, cos, pow, sqrt e sin.
É uma boa prática testar expressões aritméticas para verificar se foram codificadas
corretamente.

4.5.5. Operador de Atribuição


O comando de atribuição da linguagem C é o símbolo de igual. A expressão
abaixo, em linguagem C, significa de que lado direito do igual é valiado e atribuído
ao lado esquerdo, ou seja, a variável x é somada com a variável y e o resultado é
atribuído à variável z.

float x = 10.0, y = 20.0, z;


z = x + y;

O operador de atribuição (=) define dois lados, o lado à sua direita e o lado à sua
esquerda. O seu significado não é o de igualdade matemática entre os dois lados.

= – operador de atribuição da Linguagem C

A atribuição significa que o lado direito é avaliado e seu resultado é escrito no


Programação Básica com Linguagem C 68

lado esquerdo. O valor que o lado esquerdo possuía, antes da atribuição, é perdido,
dando lugar ao valor do lado direito.
No caso do comando z = x + y temos a variável z, x e y são regiões na
memória da máquina do tamanho do tipo float. Na região correspondente a x foi
escrito o valor 10.0. Na região correspondente a y foi escrito o valor 20.0. A região
correspondente a z permanece sem valor inicial17. Para avaliar a expressão x + y, a
CPU busca os valores destas variáveis na memória principal, faz a soma das duas e
obtém o valor 30.0. O lado direito tem valor igual a 30.0 e está guardado na CPU.
Em seguida a CPU escreve o valor 30.0 na região de memória de nome z, ou seja, a
CPU atribui o valor 30.0 ao nome z.

atribuir – a operação de escrever na memória da máquina.

Pode–se dizer que atribuir é a operação de escrever na memória da máquina.


A sintaxe do comando de atribuição da Linguagem C é:

variavel = expressao

A variável pode ser char, int, float ou outro tipo válido. A expressão pode ser
lógica ou aritmética ou mista.
O operador de atribuição divide uma expressão em dois lados, o lado esquerdo e
o lado direito. O lado esquerdo do operador de atribuição (=) é chamado de lvalue,
e o lado direito é denominado rvalue.

lvalue = rvalue
lvalue – denominação do lado esquerdo do operador de atribuição
rvalue – denominação do lado direito do operador de atribuição

O lvalue não podem ser constante porque a atribuição modifica o seu valor,
ocorre escrita na memória RAM.
O lvalue é uma variável para que possa ter seu valor modificado, pois o
operador de atribuição requer escrita na memória RAM.
O rvalue podem ser ou conter constantes e/ou variáveis porque seus valores não
são alterados, são apenas usados, ocorre apenas leitura da memória RAM.
Os rvalues devem possuir valores válidos para que os lvalues correspondentes
sejam válidos.
Na programação tem uma regra: entra lixo, sai lixo.
Como bons profissionais, essa regra tem que mudar para: entra lixo, sai um
aviso que entrou lixo.
Acostumem–se a verificar se os valores iniciais dos rvalues foram atribuídos ou

17 O valor da variável z é desconhecido pelo programador mas a região da memória associada a esta variável possui 0s e 1s,
usualmente chamado lixo da memória.
Programação Básica com Linguagem C 69

lidos.

Exemplo 4.20 Operador de atribuição em C.


#include <stdio.h>
int main ( void ){
float x = 10.0, y = 20.0, z;
z = x + y;
printf(" z = %f", z );
return 0;
}
O comando de atribuição C determina dois lados, o direito e o esquerdo. De modo
geral, o lado direito é denominado rvalue e o lado esquerdo é denominado lvalue.

Exemplo 4.21 O programa abaixo contém erros.


#include <stdio.h>
int main ( void ){
float x = 10.0, y, z;
z = x + y;
printf(" z = %f", z );
return 0;
}
A variável x é um rvalue e possui valor inicial válido. A variável y é um rvalue mas
não possui um valor inicial válido. Ao avaliar a expressão x + y, o programa vai
operar sobre y cujo valor é indefinido, produzindo valores indefinidos.
Teste este programa é veja o resultado. Talvez o compilador de um aviso
(warning) indicado a falta de valor inicial para y.

4.5.6. Abreviaturas do Comando de Atribuição


A Linguagem C tem a opção de abreviar alguns comandos de atribuição.
É comum expressões do tipo x = x + 1, incremento de 1. Está expressão pode
se abreviada para x++ ou ++x, conforme a necessidade.
No Exemplo 4.22 estão outras abreviações do comando de atribuição.

Exemplo 4.22 Abreviações do Comando de Atribuição


Expressão Matemática Abreviação em Linguagem C
i=i+1 i++
i=i–1 i––
S=S+x S += x
S=S–x S –= x
Programação Básica com Linguagem C 70

S=S*x S *= x
S=S/x S /= x
As abreviações do comando de atribuição são opcionais.
A ordem importa, x = i++ é diferente de x = ++i:

• x = i++ atribui e depois incrementa


• x = ++i incrementa e depois atribui

Em expressões mais elaboradas, recomenda–se aplicar a regra e testar o código.

4.5.7. Transbordamento de Dados


Ocorre o transbordamento de dados (buffer overflow e buffer underflow) ocorre
quando se faz acesso indevido ou sobrescreve a memória e corrompe endereços
adjacente a ela. Este problema é comum em C porque ela permite acesso de baixo
nível, não checa limites superiores ou inferiores de dados e não proveem proteção
contra acesso indevido ou sobrescrita da memória.
Um exemplo são as strings e o outro são os vetores e matrizes (arrays), ambos
são indexados. Se os valores dos índices vão além do permitido pode ocasionar
acesso indevido à memória. Cabe ao programador evitar tais erros.

Pesquise na web: transbordamento de dados

4.5.8. Promoção de Tipo de Dado em Expressões


Expressões que possuem operandos de vários tipos são tem seus valores
promovidos para o mesmo tipo. O compilador faz esta promoção automaticamente
conforme ilustrado pela Figura 4.7
Programação Básica com Linguagem C 71

Figura 4.7 Exemplo de promoção de tipos em expressões.

De modo geral, a ordem da promoção dos tipos de dados em expressões, exceto


os tipos com modificador unsigned, Figura 4.8.

Figura 4.8 Ordem de promoção dos tipos de dados em expressões.

promoção de tipo – operando de menor tamanho ou precisão é


promovido automaticamente para o de maior tamanho ou
precisão (implicitamente)

O Algoritmo de Promoção de Tipo da Linguagem C, em detalhes, é o seguinte:


Algoritmo de Promoção de Tipo da Linguagem C

se um dos operandos é long double


então o outro é promovido a long double
senão se um dos operandos é double
então o outro é promovido a double
senão se um dos operandos é float
então o outro é promovido a float
senão se um dos operandos é unsigned long
então o outro é promovido a unsigned long
senão se um dos operandos é long
então o outro é promovido a long
senão se um dos operandos é unsigned int
então o outro é promovido a unsigned int

Caso especial adicional: Se um operando é long e o outro é unsigned int,


e se o valor da unsigned int não pode ser representado por um long ambos
os operandos são promovidos para unsigned long.

Exercício 4.2 Faça um programa para testar o Algoritmo de Promoção de Tipo


(incluindo com o modificador unsigned) da Linguagem C.
Programação Básica com Linguagem C 72

4.5.9. Cast
Como já visto, a divisão de dois números inteiros retorna um número inteiro.

int a = 9, b = 5;
float c;
c = a/b;

O valor de c é igual a 1.000000 porque não há promoção de tipo, a e b são int.


Ao dividir inteiros, ou expressões matemáticas que resultem em inteiros,
programas em C truncam os resultados, abandonam a parte fracionária, ficando
apenas com a parte inteira.
Para obter os resultados corretos é necessário converter o numerador ou o
denominador, neste caso em float, manualmente (explicitamente), um deles é
suficiente:

c = float(a)/b;

ou

c = a/float(b);

ou ainda, sem necessidade,

c = float(a)/float(b);

O valor de c é igual a 1.800000. Observe que c = float(a/b) resultando em c =


1.000000 e c = float(a)/float(b) resultando em c = 1.800000.
Converter o valor de um tipo de dados para outro é denominado cast. Ao
executar um cast de tipos, o valor do operando é forçado a ser de um tipo
particular, não importando a regra de conversão de tipos. Sua sintaxe depende do
operando, dada por:

(tipo de dado) constante


(tipo de dado) variável
(tipo de dado) (expressão)
(tipo de dado) (função)

cast de tipo – operador que altera o tipo de um operando


manualmente (explicitamente) pelo programador

O cast de tipo tem a maior precedência possível, ele altera o valor de um


operando sem mudar o tipo da variável. O tipo das variáveis é definido uma vez na
declaração e não pode ser alterado.
Programação Básica com Linguagem C 73

Exemplo 4.23 Convertendo valores int para float.


#include <stdio.h>
int main ( void ){
int n;
printf( "Digite o valor int:" );
scanf( "%d", &n );
printf(" float(n) = %f", float(n) );
return 0;
}
Observe que o formato no scanf é para variável de tipo float pois o valor da
variável n foi alterado (momentaneamente) a para o seu correspondente valor
float.
A variável n continua sendo do tipo int, apenas o seu valor foi alterado para float.

Exemplo 4.24 Convertendo valores float para int e char.


#include <stdio.h>
int main ( void ){
float x;
printf( "Digite o valor float:" );
scanf( "%f", &x );
printf("\n int (x) = %d", int(x) );
printf("\n char(x) = %c", char(x) );
return 0;
}
A variável x continua sendo do tipo float, apenas o seu valor foi alterado para int e
char, conforme o caso.

Exercício 4.3 Faça um programa para avaliar o cast de: char → int → float → double.

Exercício 4.4 Faça um programa para avaliar o cast de: char → int → float → double,
incluindo os tipos unsigned

Exercício 4.5 Faça um programa para avaliar o cast de: char → int → float → double,
incluindo os tipos unsigned, short e long.

Exercício 4.6 Explique os valores impressos por este programa:


#include <stdio.h>
int main ( void ){
int a = 9, b = 5; float c;
c = a/b; printf("\n c = %f", c );
Programação Básica com Linguagem C 74

c = float(a)/b; printf("\n c = %f", c );


c = float(a)/float(b); printf("\n c = %f", c );
c = a/float(b); printf("\n c = %f", c );
c = float(a/b); printf("\n c = %f", c );
return 0;
}

4.5.10. Funções Matemáticas


A Biblioteca Padrão possui muitas funções matemáticas para tratamento
numérico, Tabela 4.16. Nesta tabela estão listadas as funções comumente usadas.
O tipo de dados default das funções matemáticas é o double. Nas funções
trigonométricas os ângulos são em radianos.

Tabela 4.16 Principais funções matemáticas da Biblioteca Padrão, requer #include


<math.h>
Função Significado
sin, cos, tan Funções trigonométricas
asin, acos, atan Funções trigonométricas inversas
sinh, cosh, tanh Funções hiperbólicas
sqrt Raiz quadrada
exp Função exponencial
log Logaritmo natural
log10 Logaritmo na base 10
abs Valor absoluto, parâmetro int
fabs Valor absoluto, parâmetro double
pow(x,y) Potenciação (xy)

Protótipos:

int abs (int i );


double fabs (double d );
double sin (double arco); // arco em radianos
double cos (double arco);
double tan (double arco);
double asin (double arco);
double acos (double arco);
double atan (double arco);
double ceil (double num ); // arredonda para cima
double floor(double num ); // arredonda para baixo
double log (double num );
double log10(double num );
Programação Básica com Linguagem C 75

double pow (double base, double exp);


double sqrt (double num );

Pesquise na web: math.h

4.5.11. Gerando Dados de Entrada


A Biblioteca Padrão possui a função int rand( void ) que gera um número inteiro
aleatório entre 0 e a constante RAND_MAX, requer < stdlib.h>.
Pode-se usar o operador módulo para limitar o valor a uma faixa menor.
Esta função é muito útil para gerar dados de entrada, evitando digitações
enfadonhas.

Exemplo 4.25 O programa gera dados de entrada.


#include <stdio.h>
#define MAX 10
int main ( void ){
int x = rand() % MAX; // reduz a faixa para 0 a MAX-1.
printf(" x = %d", x );
return 0;
}

4.5.12. Estrutura e Estilo


A Linguagem C permite a inclusão de espaços, tabulações e quebras de linha
extras mas eles são ignorados pelo compilador, exceto em strings).

Recomenda-se um comando por linha para melhor legibilidade do programa


fonte. Quando for necessário, divida a instrução em mais de uma linha.
Recomenda-se a indentação, que consiste deslocar para direita os comandos de
um bloco. Desta forma, melhora a visualização do programa-fonte e a posição
relativa dos blocos e seus comandos.

4.5.13. Resumo
Programação Básica com Linguagem C 76

Figura 4.9 Mapa mental de Variável (até este capítulo).

4.5.14. Exercícios

1. Preencha o quadro abaixo:

Expressão Matemática Correspondência em Linguagem C


C=M (1+i)n
1 1
x= 2 3
− 2 2
a (1−b) a (1−b)
2 2
r (1+ r−r )
v= 2
(1−r )
2
−b−√ b −4 ac
x=
2a
a1 + a2+ a3 +a 4
m=
4
a+b a−b
c=2 cos ( )sen ( )
a−b a+ b
1
y= [cos(a +b)+cos (a−b)]
2
2
mv
Ec =
2
2 2 2 2
( x1−m) +( x2 −m) +( x3 −m) +(x 4−m)
s=
√ 4
n n


3+ 4+
2 +n 2 3
(x 1−m) +( x2−m) +(x 3−m)
u=
n
3+
3
2
1 x−m
1 − ( )
f= e 2 s

√2π s²
x

a−1 b
x e
f= a b
b +a
b
x
−( )
b−1 a
bx e
y= b
a
Programação Básica com Linguagem C 77

p−1 q−1
v (1−v )
z= p+ q
(1+ v)
b
x
−( )
b−1 a
bx e
g= b
a
q2 3 q
x=
−b
3a
2
+

1+
4
2a
R2
R1

+p −
3

4
√ 2

V 2=V 1 ( )
1 R2
+ +1
G GR 1
(−1)n 2 n−1
y= 2 n+1
( x+ y)
(2n−1)
2. Entrar com valores para a, b, c, imprimir o valor de x, sabendo–se que
b
x=a+ −2×(a−b−c) .
a+ b
3. Entrar com valores para a, b, c, d, imprimir o valor de f, sabendo–se que

f=
√cos (a)+ sen(b) .
ec −ln (d)
4. Entrar com valores para a, b, c, imprimir o valor de x, sabendo–se que
2
−b− √ b −4 ac
x= .
2a
5. Entrar com valores para m, s, x, imprimir o valor de f, sabendo–se que
2
1 x−m
1 − ( )
f= e 2 s
.
√2 π s ²
6. Embora por lei não possa obrigar o cliente a pagar gorjeta. Fazer um algoritmo que
leia o valor da despesa realizada em um restaurante e imprima o valor total com a
gorjeta.
7. Alguns tributos usa a base de cálculo salário–mínimo. Fazer um algoritmo que leia o
valor do salário–mínimo e o valor do salário de uma pessoa. Calcular e imprimir
quantos salários–mínimos ela ganha.
8. Preencha o quadro abaixo com a expressão lógica correspondente em C:

Intervalo de números reais Expressão Lógica

9. Crie uma condição lógica para de x ∊ (a,b) união x ∊ (c,d).


10.Crie uma condição lógica para de x ∊ (a,b) interseção x ∊ (c,d).
11.Crie uma condição lógica para de x < a união y ∊ (c,d).
12.Ler a massa e a aceleração de um corpo e escrever a sua força (F=m*a).
Programação Básica com Linguagem C 78

13.Ler a massa e a velocidade de um corpo e escrever a sua energia cinética


(E=m*v2/2).
14.Ler o salário de um funcionário e imprimi–lo com um aumento de 15%.
15.Ler o preço de um produto e imprimi–lo com um desconto de 15%.
16.Ler um valor real e escrever apenas a parte inteira deste número.
17.Ler um valor real e escrever apenas a parte decimal deste número.
18.Ler um valor real x e verificar se cos2x+sen2x = 1, teste para float, double e long
double.

4.6. Estrutura Condicional


A estrutura condicional executa determinados códigos de programação
baseando–se numa lógica de comparação. O fluxo de controle do programa é
alterando seletivamente com base em alguma condição booleana.
As estruturas condicionais são também conhecidas como estrutura de decisão
ou de seleção.

booleano – indica os valores lógicos {false, true}


condição – expressão cujo valor resultante é booleano
estrutura condicional – estrutura de desvio do fluxo de controle que
executa diferentes comandos de acordo com uma condição

A Linguagem C possui duas de estruturas condicionais, representadas pelos


comandos if/else e switch/case.

4.6.1. Comando if/else


O comando if/else permite selecionar uma decisão dentre duas alternativas. A
decisão é baseada no valor de uma expressão lógica de controle. Ele é constituído
por dois blocos, como pode ser visto na Figura 4.10, o bloco do if (executado de a
condição for true) e o bloco do else (executado de a condição for false), só um dos
blocos é executado, ou o do if ou o do else.
Programação Básica com Linguagem C 79

Figura 4.10 Fluxograma do comando if/else.

A sintaxe do comando if/else é:


if( condição ){ // bloco do if – executado quando condição é true
<lista de comandos do bloco do if>
{
else{ // bloco do else – executado quando condição é false
<lista de comandos do bloco do else>
}
Quando o fluxo de controle do programa encontra o identificador if ele avalia a
condição, que pode ser verdadeira ou falsa. Se a condição é verdadeira, o bloco de
código do if é executado e não executa o bloco do else. Se a condição é false, o
bloco de código do else é executado e não executa o bloco do if. Em ambos os
casos, após a execução de um dos blocos de código, o fluxo de controle do
programa é retornado.
O bloco do else é opcional e pode ser omitida. Caso omitida, a estrutura é
chamada de if simples; caso contrário é chamada if composto.

Exemplo 4.26 Programa C para verificar se escrever na tela se um número inteiro é


para ou ímpar.
Matematicamente, seja x um número inteiro, se x % 2 == 0 então x é par, caso
contŕario, x é ímpar.
O programa pode ser resolvido com um if composto.
Basta declarar uma variável inteira para armazenar o valor do número inteiro a ser
lido pelo teclado e usar um if composta com a condição: valor lido % 2 == 0.
Abaixo estão apresentados o programa e sua representação em fluxograma.
Programação Básica com Linguagem C 80

#include <stdio.h>
int main( void ){
int x;
printf( "Digite um numero inteiro: " );
scanf( "%d", &x );
if( x % 2 == 0 ){
printf("numero lido e par" );
}
else{
printf("numero lido e impar" );
}
return 0;
}

Exercício 4.7 O programa abaixo resolve o Exemplo 4.26?


#include <stdio.h>
int main( void ){
int x;
printf( "Digite um numero inteiro: " );
scanf( "%d", &x );
if( x % 2 ) printf("numero lido e impar" );
else printf("numero lido e par" );
return 0;
}

Exercício 4.8 Reescreva o fluxograma do Exemplo 4.26 com dois comandos a


menos.

Exemplo 4.27 Classificar se um brasileiro é maior ou menor de idade.


Na legislação, o define se um brasileiro é de maior ou de menor é a sua idade –
esta e á variável da condição.
A legislação estabelece que a maioridade é alcançada aos 18 anos – com isso
pode–se definir a condição booleana.
Logo é necessário saber a idade da pessoa em anos e compará–la com o valor 18.
Se a idade for maior ou igual a 18, a pessoa é de maior pois a comparação resulta
em um valor lógico Verdade.
Basta declarar uma variável para receber o valor da idade da pessoa, o tipo int é
suficiente e o mais adequando. Ler o valor da idade pelo teclado e compará–lo com
Programação Básica com Linguagem C 81

o valor padrão que é igual a 18, para isso utiliza–se o comando if, como abaixo
indicado.
#include <stdio.h>
int main( void ){
int idade;
printf( "Digite a idade do cidadao brasileiro em anos: " );
scanf( "%d", &idade );
if( idade >= 18 ){
printf(" o cidadao e de maior" );
}
else{
printf(" o cidadao e de menor" );
}
return 0;
}

O comando if pode ser aninhado. Pode–se ter if dentro de if, permitindo tomar
decisões complexas.

Exemplo 4.28 Classificar um brasileiro em voto obrigatório, voto facultativo e não


vota.
Na legislação, o que define se um brasileiro vota é a sua idade, com quatro faixas
de decisão:
a) idade menor do que 16 – não vota
b) idade entre 16 e 17, inclusive, – voto facultativo
c) idade entre 18 e 70, inclusive – voto obrigatório
d) idade maior do que 70 – voto facultativo
Logo é necessário saber a idade da pessoa em anos e enquadrá–la na faixa
correspondente.
Basta declarar uma variável para receber o valor da idade da pessoa, o tipo int é
adequando. Ler o valor dado pelo teclado e avaliar a qual faixa pertence, para isso
utiliza–se comandos if aninhados, como abaixo indicado.
#include <stdio.h>
int main( void ){
int idade;
printf( "Digite a idade do eleitor brasileiro em anos: " );
scanf( "%d", &idade );
if( idade < 16 ){
printf(" o cidadao não vota" );
}
else{
if( idade < 18 ){
Programação Básica com Linguagem C 82

printf(" o voto e facultativo" );


}
else{
if( idade < 71 ){
printf(" o voto e obrigatorio" );
}
else{
printf(" o voto e facultativo" );
}
}
}
return 0;
}
Observe a edentação do código. Esta técnica é muito útil e serve para verificar que
comando pertence a cada bloco.
Esta não é única solução.

Exercício 4.9 Refazendo exemplos


1. Proponha outros dois programas para o Exemplo 4.28 e teste seus códigos.
2. Faça um fluxograma do if simples.
3. Faça um fluxograma do Exemplo 4.28.
4. Tomando como base , a Figura 1.7, faça de um if composto no qual há uma
estrutura sequencial a) apenas no bloco do if; apenas no bloco de eles; e c)
em ambas.

Exemplo 4.29 Faça um programa em C que leia um número inteiro do teclado e


verifique se ele é múltiplo de 3 ou 4 mas não de 5.
Pode–se usar a técnica “dividir para conquistar”:

• Condição para que x seja múltiplo de 3: x % 3 == 0


• Condição para que x seja múltiplo de 4: x % 4 == 0
• Condição para que x seja múltiplo de 5: x % 5 == 0

Proposta de uma expressão lógica para “múltiplo de 3 ou 4 mas não de 5”:


(múltiplo de 3 ou múltiplo de 4 ) e não (múltiplo de 5 )
Em C temos: (x % 3 == 0 || x % 4 == 0 ) && !( x % 5 == 0)
Testes:

• x = 0 não é “múltiplo de 3 ou 4 mas não de 5”


• x = 3 é “múltiplo de 3 ou 4 mas não de 5”
• x = 4 é “múltiplo de 3 ou 4 mas não de 5”
• x = 12 é “múltiplo de 3 ou 4 mas não de 5”
Programação Básica com Linguagem C 83

• x = 20 não é “múltiplo de 3 ou 4 mas não de 5”


• x = 48 é “múltiplo de 3 ou 4 mas não de 5”
• x = 60 não é “múltiplo de 3 ou 4 mas não de 5”

Basta declarar uma variável para receber o valor do número inteiro, seja x o nome
desta variável.
Ler o valor de x do teclado e avaliar a expressão (x % 3 == 0 || x % 4 == 0 ) && !
( x % 5 == 0) e decidir, como o programa abaixo.
#include <stdio.h>
int main( void ){
int x;
printf( "Digite o valor de x: " );
scanf( "%d", &x );
if( (x % 3 == 0 || x % 4 == 0 ) && !( x % 5 == 0) ){
printf(" %d e multiplo de 3 ou 4 mas nao de 5", x );
}
else{
printf(" %d nao e multiplo de 3 ou 4 mas nao de 5", x );
}
return 0;
}
Teste bem esta solução para verificar se ela não tem algum erro de lógica!

Limitações matemáticas dos tipos de dados


#include <stdio.h>
int main( void ){
int k = 47;
double x = 10.9,
w = x/k,
z = (k*x)/(k*k);
if( w-z != 0 ) printf( "\n diferente de zero" );
return 0;
}

x k∗x
Matematicamente, os valores de w= e z= são iguais, logo
k k∗k
w−z=0 .
Mas como os tipos de dados da Linguagem C são limitados pela precisão da
máquina, o cálculo computacional de w-z = -0.000000000000000028; como
w-z != 0, programa vai escrever na tela: diferente de zero.

A solução para comparação de ponto flutuante com zero 0 é não resolvê-lo, e


sim contornar o problema.
Programação Básica com Linguagem C 84

Seja um double, por exemplo x, para saber se x == 0.0 é melhor não compará-
los. Para contornar este problema, pode-se verificar se fabs(x) > 0.0. O valor fabs(x)
é positivo ou nulo. Se x for muito pequeno, pode ser muito pequeno positivo ou
muito pequeno negativo. A condição fabs(x) > 0.0 indica se x é exatamente 0.0 ou
não.

Para verificar se um valor ponto flutuante (float, double e long double) é


nulo (zero) recomenda–se testar se o seu valor absoluto é maior do que
zero (0.0), da forma:
#include <stdio.h>
int main( void ){
int k = 47;
double x = 10.9,
w = x/k, // matematicamente w-z = 0
z = (k*x)/(k*k); // computacionalmente w-z ≠ 0
if( fabs(w-z) > 0.0 ) printf("\n diferente de zero ");
else printf("\n igual a zero ");
return 0;
}
Para a máquina, um double de valor zero é diferente de um int de valor
zero mas, para nós humanos tanto faz, zero é zero. Resumindo, para a
máquina 0 é int e 0.0 é float, há situações em 0 ≠ 0.0.
Uma expressão equivalente a fabs(x) > 0.0 é ( (x > 0.0) || (x < 0.0) ).

Exercício 4.10 Escreva um programa para verificar se a expressão (x % 3 == 0) ||


(x % 4 == 0 ) && ( x % 5 != 0) resolve o Exemplo 4.29, teste seu código. Justifique
os resultados.

4.6.2. Comando Ternário (?:)


O operador ternário é uma forma abreviada para escrever o comando if/else nas
situações em que o lvalue é o mesmo tanto no if quanto no else.

Exemplo 4.30 Operador ternário.


No if–else abaixo, a variável z é o lvalue tanto no if quanto no else.
if( x > 0 ){
z = sqrt(x);
}
else{
z = 0.0;
}
Sendo assim, o if–else pode ser abreviado por:
z = x > 0 ? sqrt(x) : 0.0;
Programação Básica com Linguagem C 85

Ou seja, se x > 0 for Verdade então z = sqrt(x) e, caso contrário, z = 0.0;

Exercício 4.11 O programa abaixo está correto? Justifique os resultados.


#include <stdio.h>
int main( void ){
int x;
printf( "Digite um numero inteiro: " );
scanf( "%d", &x );
x % 2 ? printf("x e impar") : printf("x e par" );
return 0;
}

4.6.3. Comando switch


Por outro lado, o comando switch é uma maneira simplificada de tomar decisão
com múltiplas escolhas. No switch, uma variável é sucessivamente testada contra
uma lista de inteiros ou caracteres e, quando uma associação é encontrada, estes
comandos são executados.
Para mais de uma escolha, pode–se usar o comando switch, sua forma é:

switch( seletor ){
case valo1 : <bloco de comandos da opção 1>
break;
case valo2 : <bloco de comandos da opção 2>
break;
...
case valon : <bloco de comandos da opção n>
break;
default : <bloco de comandos do default>
}
A Figura 4.11 ilustra o comando witch.

Figura 4.11 Fluxograma do comando switch.

A linguagem C aceita apenas seletores do tipo char ou do tipo int (signed,


unsigned, short).
Programação Básica com Linguagem C 86

Exemplo 4.31 Identifica o nome do dia da semana a partir do seu número, usando
switch.
#include <stdio.h>
int main( void ){
int dia;
printf( "Digite um valor de 1 a 7: " );
scanf( "%d", &dia );
switch( dia ){
case 1 : printf("domingo");
break;
case 2 : printf("segunda–feira");
break;
case 3 : printf("terca–feira");
break;
case 4 : printf("quarta–feira");
break;
case 5 : printf("quinta–feira");
break;
case 6 : printf("sexta–feira");
break;
case 7 : printf("sabado");
break;
default: printf("dia invalido");
}
return 0;
}
Ao encontrar o comando switch, o programa executará o comando que for igual a
valor da variável dia corresponde ao de alguma constante do case, o comando
break encerra o switch. Caso contrário será executado o comando default que é o
printf("dia invalido") e encerra o switch.
Cada comando case do switch deve ser encerrado pelo break. O comando default
não possui break, e deve ser o último do switch.
Sempre alguma opção de switch é selecionada, na falta de opções validas, o
default é executado – corresponde ao nosso Plano B.

O comando switch por ser escrito usando if/else compostos aninhados, como
mostrado do Exemplo 4.32.

Exemplo 4.32 Identifica o nome do dia da semana a partir do seu número, usando
if/else compostos aninhados.
#include <stdio.h>
int main( void ){
int dia;
Programação Básica com Linguagem C 87

printf( "Digite um valor de 1 a 7: " );


scanf( "%d", &dia );
if( dia == 1 ) printf("domingo");
else if( dia == 2 ) printf("segunda–feira");
else if( dia == 3 ) printf("terca–feira");
else if( dia == 4 ) printf("quarta–feira");
else if( dia == 5 ) printf("quinta–feira");
else if( dia == 6 ) printf("sexta–feira");
else if( dia == 7 ) printf("sabado");
else printf("dia invalido");
return 0;
}
Nas implementações acima, o uso do switch é o mais indicado pois apresenta
melhor legibilidade comparado a dos if’s aninhados.

Exemplo 4.33 Calculadora de quatro operações.


#include <stdio.h>
int main( void ){
char op;
float a, b, c;
printf( "Calculadora + – * / \n\n\n" );
printf( "Digite o valor do primeiro operando numerico: " );
scanf ( "%f", &a );
printf( "Digite o valor do segundo operando numerico: " );
scanf ( "%f", &b );
printf( "Digite a operacao + – * / " );
scanf ( " %c", &op );
// o espaco antes do %c evita ler a tecla ENTER
switch( op ){
case '+': c = a + b; break;
case '–': c = a – b; break;
case '*': c = a * b; break;
case '/': if( fabs(b) > 0.0 ) c = a / b;
else{ printf("\n >>> divisao por zero \b\b\b");
return 1;
}
default: printf("\n ::: operacao invalida \b");
return 2;
}
printf( "\n %f %c %f = %f", a, op, b, c );
return 0;
Programação Básica com Linguagem C 88

}
O código deve ser escrito com cuidado para evitar divisão por zero. O programa
testa se o valor absoluto do denominador é maior do zero.
Como o denominador é do tipo float, a expressão if( b == 0.0 ) pode ser usada
mas a if( fabs(b) > 0.0 ) é mais segura.
Nas implementações acima, o seletor do switch é do tipo char.
Para ler um valor char corretamente usando scanf é necessário incluir um espaço
antes de %c – scanf( " %c", &op ) – isto se deve ao fato de que a tecla ENTER é
tratada como caractere e qualquer ENTER deve ser ignorado.
O \b no formato do printf faz o computador emitir um beep (se o alto–falante
estiver funcionando e ligado).

Exercício 4.12 Fluxogramas


5. Faça um fluxograma do Exemplo 4.31.
6. Faça um fluxograma do Exemplo 4.32.
7. Faça um fluxograma do Exemplo 4.33.
8. Reescreva o Exemplo 4.33 usando if/else compostos aninhados.

4.6.4. Exercícios

1. Entrar com um valor e dizer a qual mês do ano.


2. Leia um ponto (x,y), coordenadas de um plano, e informar em qual quadrante ele
está situado, se está em um dos eixos ou localizado na origem.
3. Leia os seus coeficientes de uma equação do segundo o grau e escreva um
programa para calcular suas as raízes. Faça também o seu fluxograma.
4. Faça um programa em C que leia um número inteiro do teclado e verifique se é:
a) positivo e menor do que 100
b) divisível por 3 ou por 5 ou por 7
c) múltiplo de 4 ou 6 ou 10
d) múltiplo de 4 e 6 e 10
e) múltiplo de 4 e 6 ou 10
f) ı ́mpar
5. Faça um programa que receba quatro notas de um aluno, calcule e mostre a média
aritmética das notas e a mensagem de aprovado ou reprovado, considerando para
aprovação média 7.
6. Faça um programa que receba três notas, calcule e mostre a média aritmética e a
mensagem conforme descrição abaixo:
a) média de 0,0 a 4,9: reprovado
b) média de 5,0 a 6,9: exame
c) média de 7,0 a 10: aprovado
7. Faça um programa que receba dois números e mostre o menor.
8. Faça um programa que receba três números e mostre o maior.
9. Faça um programa que receba quatro números e mostre o maior.
Programação Básica com Linguagem C 89

10.Faça um programa que receba dois números e mostre–os em ordem crescente.


11.Faça um programa que receba três números e mostre–os em ordem crescente.
12.Faça um programa que receba quatro números e mostre–os em ordem crescente.
13.Faça um programa para calcular o Imposto de Renda de Pessoa Física (IRPF),
consulte na web as regras para este cálculo.
14.Faça um programa que receba dois números e execute as operações listadas a
seguir, de acordo com a escolha do usuário. Se a opção digitada for inválida, mostre
uma mensagem de erro e termine a execução do programa. Lembre–se de que não
há divisão por zero.
a) escolha a: média dos números
b) escolha b: diferença do maior pelo menor
c) escolha c: produto dos números
d) escolha d: divisão do primeiro pelo segundo.
15.Faça um programa que receba dois números e execute uma das operações listadas a
seguir, de acordo com a escolha do usuário. Se for digitada uma opção inválida,
mostre mensagem de erro e termine a execução do programa. As opções são:
a) o primeiro número elevado ao segundo número
b) raiz quadrada de cada um dos números
c) raiz cúbica de cada um dos números.
16.Uma empresa decide dar um aumento de 30% aos funcionários com salários
inferiores a R$ 5000,00. Faça um programa que receba o salário do funcionário e
mostre o valor do salário reajustado ou uma mensagem, caso ele não tenha direito
ao aumento.
17.Faça um programa que receba a altura e o sexo de uma pessoa e calcule e mostre
seu peso ideal, utilizando as seguintes fórmulas: a) para homens: 72.7 h – 58, b) para
mulheres: 62.1 h – 44.7; onde h é a altura.
18.Faça um programa que receba a altura e o “peso” de uma pessoa e calcule e mostre
seu Índice de Massa Corporal IMC.
19.Escreva um programa que leia as medidas dos lados de um triângulo e escreva se
ele é equilátero, isósceles ou escaleno.
20.Faça um programa que informe se é possível comprar um produto de valor X reais
com a quantidade reais de uma carteira que contenha:
a) M1 moedas de R$ 1,00
b) N1 notas de R$ 2,00
c) N2 notas de R$ 5,00
d) N3 notas de R$ 10,00
e) N4 notas de R$ 50,00
f) N5 notas de R$ 100,00

Exercício 4.13 Existência de Triângulo


Sabendo que para construir um triângulo é necessário que a medida de qualquer
um dos lados seja menor que a soma das medidas dos outros dois e maior que o
valor absoluto da diferença entre essas medidas, faça um programa em C que
receba três valores e informe se eles formam um triângulo. Consulte a Biblioteca
Padrão para cálculo do valor absoluto.
Programação Básica com Linguagem C 90

Exercício 4.14 Problema das Latas de Tinta


Faça um programa em C que calcule o custo financeiro (C) e a quantidade de latas
de tinta (Q) necessárias para pintar tanques cilíndricos de combustível de altura
(H) e o raio da base (R) do cilindro, ambos em metros, sabendo que:
a) a lata de tinta custa X unidades monetárias
b) cada lata contém Y litros de tinta
c) a cada litro de tinta pinta Z metros quadrados

Dados de entrada: X, Y, Z, H e R.
Dados de saída: C e Q.

Relações úteis:
a) custo é dado por quantidade de latas*X
b) quantidade de latas é dada por quantidade total de litros/Y
c) a quantidade total de litros é dada por área do cilindro/Z
d) área do cilindro é dada por área da base + área lateral
e) área da base é (PI*R2)
f) a área lateral é altura*comprimento: (2*PI*R*H)
g) PI é uma constante de valor conhecido: 3,141592
Fonte: http://thiagoccampos.blogspot.com/2012/03/construa–um–algoritmo–que–calcule.html

Exercício 4.15 Matemática, Páscoa e Programação


O matemático Johann Friederich Carl Gauss propôs um método para determinar as datas de Páscoa,
cujas regras foram definidas no Concílio de Nicéia (325 E.C.).

Conforme definido, a Páscoa deve ser celebrada no domingo seguinte à primeira lua cheia da
Primavera (na Europa). Gauss desenvolveu uma regra prática para calcular a data da Páscoa no
calendário gregoriano, a partir de 1583.

Considere A como sendo o ano, e m e n dois números que variam ao longo do tempo de acordo
com a seguinte tabela:

Ano Valores
1583–1699 m=22, n=2
1700–1799 m=23, n=3
1800–1899 m=23, n=4
1900–2099 m=24, n=5
2100–2199 m=24, n=6
Considere também:

a) o resto da divisão de A por 19


b) o resto da divisão de A por 4
c) o resto da divisão de A por 7
d) resto da divisão de 19a+m por 30
e) o resto da divisão de 2b+4c+6d+n por 7

Então a Páscoa será no dia 22+d+e de março ou d+e–9 de Abril

Observações:

a) O dia 26 de abril deve ser sempre substituído por 19 de abril.


Programação Básica com Linguagem C 91

b) O dia 25 de abril deve ser substituído por 18 de abril se d=28, e=6 e a>10.
Faça um programa em C para calcular a páscoa de qualquer ano no intervalo de 1583 a 2199.
Fonte: http://www.somatematica.com.br/mundo/pascoa.php

Exercício 4.16 Movimento do Cavalo


O cavalo é colocado no tabuleiro vazio. Considere que ele se move em um padrão
assemelhado a um "L". Dadas as posições iniciais do cavalo, faça um programa em
C que mostre todas as posições possíveis para as quais ele pode se mover.

Na figura abaixo, a posição inicial do cavalo é d4, e ele pode se mover para as
seguintes casas: f5, f3, e6, e2, c6, c2, b5 ou b3.

Fonte: https://sites.google.com/site/tecprojalgoritmos/problemas/Passeio–do–cavalo

Exercício 4.17 Movimento do Cavalo "Marvel"


Suponha que exista o Cavalo "Marvel", com movimento em "L" mas inicialmente ele anda p
posições vira e anda mais q posições em tabuleiro 2D. Dadas as posições iniciais do Cavalo
"Marvel", os valores de p ≥ 0 e q ≥ 0, faça um programa em C que mostre todas as posições
possíveis para as quais ele pode se mover.

Exercício 4.18 Movimento do Cavalo em 3D


Estenda o movimento do cavalo para um tabuleiro 3D e, dadas as posições iniciais
do cavalo, faça um programa em C que mostre todas as posições possíveis para as
quais ele pode se mover.

Exercício 4.19 Movimento do Cavalo "Marvel" em 3D


Estenda o movimento do Cavalo "Marvel" para um tabuleiro 3D e, dadas as posições iniciais do
cavalo, os valores de p ≥ 0 e q ≥ 0, faça um programa em C que mostre todas as posições possíveis
para as quais ele pode se mover.

Exercício 4.20 Qual problema este programa resolve?


#include <stdio.h>
#include <ctype.h>
int main( void ){
char regiao, vendedor;
printf("As regiões são: Leste, Oeste e Norte\n");
printf("Informe a primeira letra da região: ");
regiao = getche();
regiao = toupper( regiao );
Programação Básica com Linguagem C 92

printf("\n");
switch( regiao ){
case 'L': printf("Vendedores são: Rafael, João e Maria\n");
printf("Informe a primeira letra do vendedor: ");
vendedor = toupper( getche() );
printf("\n");
switch( vendedor ){
case 'R': printf("Vendas: R$%d\n",10000); break;
case 'J': printf("Vendas: R$%d\n",12000); break;
case 'M': printf("Vendas: R$%d\n",14000);
}
break;
case 'O': printf("Vendedores são:Ronaldo, Lisa e Hilton\n");
printf("Informe a primeira letra do vendedor: ");
vendedor = toupper( getche() );
printf("\n");
switch( vendedor ){
case 'R': printf("Vendas: R$%d\n",10000); break;
case 'L': printf("Vendas: R$%d\n",9500 ); break;
case 'H': printf("Vendas: R$%d\n",13000);
}
break;
case 'N': printf("Vendedores são: Tomás, João e Raquel\n");
printf("Informe a primeira letra do vendedor: ");
vendedor = toupper(getche());
printf("\n");
switch( vendedor ){
case 'R': printf("Vendas: R$%d\n",5000 ); break;
case 'J': printf("Vendas: R$%d\n",9000 ); break;
case 'T': printf("Vendas: R$%d\n",14000);
}
break;
}
return 0;
}
Exercício 4.21 Faça um fluxograma do Exercício 4.20.

4.7. Estrutura de Repetição


Considere o problema: imprimir os números inteiros de 0 a 5 na tela do
computador.
Programação Básica com Linguagem C 93

Exemplo 4.34 Programa para imprimir os números inteiros de 0 a 5 na tela do


computador.
#include <stdio.h>
int main( void ){
printf( " 0 " );
printf( " 1 " );
printf( " 2 " );
printf( " 3 " );
printf( " 4 " );
printf( " 5 " );
return 0;
}
É uma solução mas sem valor técnico algum. Não tem padrão. Esta solução não é
genérica, se for necessário imprimir mais vezes como, por exemplo 1000 números
inteiros, serão necessárias mais linhas.

Exemplo 4.35 Outra solução.


#include <stdio.h>
int main( void ){
int i = 0;
printf( " %d ", i ); i++;
printf( " %d ", i ); i++;
printf( " %d ", i ); i++;
printf( " %d ", i ); i++;
printf( " %d ", i ); i++;
printf( " %d ", i ); i++;
return 0;
}
Observe que há um padrão. O valor inicial de i é zero (0) e é incrementado até 5
enquanto o printf é o mesmo em todos os comandos. Esta solução não é genérica,
se for necessário imprimir mais vezes serão necessárias mais linhas.

Para resolver problemas do tipo acima foram criadas a Estrutura de Repetição.

Se existir um comando que faça a variável i assumir automaticamente os


valores de 0 a 5, teríamos um algoritmo tecnicamente aceitável.

As estruturas de repetição executam seguidamente códigos de programação


baseando–se numa lógica de comparação. O fluxo de controle do programa é
alterando seletivamente com base em alguma condição booleana. Esta condição
Programação Básica com Linguagem C 94

também é denominada condição de parada.

estrutura de repetição – estrutura de desvio do fluxo de controle


que executa repetidamente comandos de acordo com uma condição

Estas estruturas executam uma ou mais instruções reiteradas vezes até que a
condição seja falsa. Eles permitem que programas executem um bloco de
instruções sem precisar escrevê–lo várias vezes. Eles fazem uso da condição como
um critério de parada ou de continuação, a verificar seu valor booleano antes de
iniciar a execução do bloco de comandos ou após a execução do mesmo.
A Figura 4.12 mostra o fluxograma de uma estrutura de repetição. Esta figura
mostra que o fluxo de controle, ao avaliar a condição como verdade, executa o
bloco de comando, retornando novamente à condição para avaliá–la e se ela for
verdadeira, o bloco de comando é executado. Este ciclo se repete até que, no bloco
de comando, a condição mude para false e assim, ao avaliar a condição novamente,
o fluxo de controle vai para o próximo comando.

Figura 4.12 Fluxograma de uma estrutura de repetição.

Se, no bloco de comandos, não o valor da condição para false, a estrutura é


executada sem parar, o chamado laço infinito.
As estruturas condicionais são também conhecidas como laços (loops) de
repetição.
A Linguagem C possui três estruturas de repetição, representadas pelos
comandos for, while e do/while.
O comando for é uma estrutura de repetição com variável de controle, com
início e fim bem determinado.
O while executar sua condição no seu início e o do/while avalia sua condição
no seu final. Uma faz pré–teste e a outra faz pós–teste, mas ambas não tem fim
bem determinado.
Ao final, são apenas estas estruturas mas se complementam e resolvem todos
os nossos problemas computáveis.

4.7.1. Comando for


O comando for é uma estrutura de repetição muito utilizada nos programas C.
Programação Básica com Linguagem C 95

Ele deve se usado sempre que se souber, de antemão, quantas vezes o bloco de
comandos deverá ser executado.

for – estrutura de repetição que executa seu bloco de comandos


contando de um valor inicial até um valor final.

De modo geral, o laço for possui:

1. um contador previamente declarado para controle do laço


2. um valor inicial do contador
3. uma condição para finalizar o laço
4. um bloco de comandos
5. um comando para incrementar/decrementar o contador

O valor inicial do contador, em geral, é definido no comando for, em seguida


vem a condição de parada e, por fim o incremento/decremento do contador. Sua
sintaxe é:

for( valor inicial; condição de parada; incremento ){


// bloco de comando do for
}

A Figura 4.13 é o fluxograma da estrutura de repetição for. Esta figura indica o


fluxo de controle do programa em que, a estrutura é iniciada com o comando valor
inicial e, em seguida avalia a condição, se false o for não é executado e o fluxo
continua; se true o bloco do for então executado, o fluxo segue e executa o
incremento e fecha o ciclo, voltando à condição. Este ciclo se repete até que o
bloco do for mude a condição false e assim, ao avaliar a condição novamente, o
fluxo de controle vai para o próximo comando.
Programação Básica com Linguagem C 96

Figura 4.13 Fluxograma da estrutura de repetição for.

Observe na Figura 4.13 que o comando valor inicial é executado uma única
vez; e também que a estrutura de repetição for pode não ser executado, ou seja,
ele pode ser executado zero vezes ou mais.

A estrutura de repetição for é executada zero vezes ou mais.

Exemplo de laço for com incremento do contador.

Exemplo 4.36 Estrutura de repetição for com incremento do contador.


#include <stdio.h>
int main( void ){
int contador;
for( contador = 1; contador < 5; contador++ ){
printf(" %d ", contador );
}
return 0;
}

O programa é inciado pela função main. Nela é declarada uma variável int
contador, para ser usado como contador do laço (não há necessidade de atribuir
um valor inicial para esta variável).
O programa executa o laço for em seguida.
No primeiro comando do laço (contador = 1) é atribuído o valor inicial do contador.
O laço for executa este comando uma única vez.
O segundo comando do laço é a condição de parada. Neste caso, a condição de
parada é contador < 5. Como o valor de contador é 1, a condição é true. Sendo
assim, o bloco é executado. O bloco possui apenas o comando de impressão na
tela, o valor do contador (1) é impresso na tela do computador.
Na sequência, é executado o terceiro comando do laço, o incremento. Neste caso,
o incremento é de 1 e o novo valor da variável contador é 2.
Após executar o terceiro comando do laço for, ele passa para o seu segundo
comando, a condição de parada. Como contador é igual a 2 que é menor do 5, a
condição de parada é true. Sendo assim, o bloco é executado, imprimindo o valor 2
na tela.
O laço for incrementa o contador, contador = 3. A condição 3 < 5 é true. O laço
executa o bloco – imprime 3 na tela.
O laço for incrementa o contador, contador = 4. A condição 4 < 5 é true. O laço
executa o bloco – imprime 4 na tela.
Programação Básica com Linguagem C 97

O laço for incrementa o contador, contador = 5. A condição 5 < 5 é false. O laço é


encerrado.
Após encerrar o laço, o programa retorna 0 e também encerrado.
O laço for foi executado 4 vezes, imprimindo os números inteiros de 1 a 4 na tela
do computador.

Exemplo 4.37 Programa para imprimir os números inteiros de 0 a 5 na tela do


computador.
#include <stdio.h>
int main( void ){
int i = 0;
for( i = 0; i <= 5; i++ ){
printf( "\n %d ", i );
}
return 0;
}
A figura abaixo mostra o fluxograma deste exemplo.
Nem tudo no programa é a estrutura de repetição for, ela está indicada com a cor
amarela. Nem a declaração int i e nem o return 0 fazem parte do for. A tabela
contem todos os valores que a variável i assume durante a execução do programa,
nela também estão indicadas os valores lógicos da condição i <= 5.
A estrutura de repetição ou o laço for, é executado seis (6) vezes, para i = 0, 1, 2,
3, 4, 5. uando i = 6, a condição é fasle e o programa sai do laço e executar o
próximo comando, return 0.

Esta solução é genérica, se for necessário imprimir mais vezes basta substituir o
valor 5 pela quantidade desejada.
Programação Básica com Linguagem C 98

Exercício 4.22 O programa abaixo também imprimir os números inteiros de 0 a 5


na tela do computador?
#include <stdio.h>
#define MAX 6
int main( void ){
int n;
for( n = 0; n < MAX; n++ ){
printf( "\n %d ", n );
}
return 0;
}

Exercício 4.23 Faça um programa, e também o seu fluxograma, para imprimir os


números inteiros de 0 a n na tela do computador. O valor n deve ser lido do
teclado.
Saída formatada.

Exemplo 4.38 Faça um programa para imprimir formatada a tabuada do 5 na tela


do computador.
#include <stdio.h>
int main( void ){
int i;
printf( "\n ------------" );
printf( "\n Tabuada do 5" );
printf( "\n ------------" );
for( i = 1; i < 11; i++ )
printf( "\n %2d x 5 = %2d", i, i*5 );
printf( "\n ------------" );
return 0;
}
Quando o bloco de uma estrutura possui um único comando, o {} é opcional.
O formato %2d reserva dois espaços na saída imprime resultados formato com 2
espaços.
No anexo há mais informações sobre saída formatada.

Juntando as estruturas de repetição e condicional.

Exemplo 4.39 Faça um programa para imprimir os números inteiros de 0 a 100000


na tela do computador informando quais são pares.
#include <stdio.h>
int main( void ){
Programação Básica com Linguagem C 99

int i;
for( i = 0; i <= 100000; i++ ){
printf( "\n %d ", i );
if( i % 2 == 0 ) printf( " par" );
}
return 0;
}

Exercício 4.24 O programa abaixo também imprime os números inteiros de 0 a


100000 na tela do computador informando quais são pares?
#include <stdio.h>
#define MAX 100001
int main( void ){
int i;
for( i = 0; i < MAX; i++ ){
printf( "\n %d ", i );
if( !(i % 2) ) printf( " par" );
}
return 0;
}
Exercício 4.25 Faça um programa, e também o seu fluxograma, para imprimir os
números inteiros ímpares de 0 a n na tela do computador. O valor n deve ser lido
do teclado.

Exercício 4.26 Reescreva o Exemplo 4.29 usando um comando ternário e apenas


um comando printf.

4.7.2. Algoritmos Básicos


Uma das maiores utilidades do computador é sua capacidade de contar, somar,
multiplicar calcular estatísticas, mínimos e máximos. A Tabela 4.17 estabelece o
procedimento computacional para as operações de contar, somar, média, mínimo e
máximo.

Tabela 4.17 Operações de contar, somar, média, mínimo e máximo e seus


algoritmos em que X denota a "variável de interesse"
Operação Procedimento
Crie a variável n inteira, com valor inicial zero (0). Dentro da
Contar estrutura de repetição coloque o comando n++. Ao sai do laço o
valor de n é o número de ocorrências ou a contagem total.
Crie a variável S, com valor inicial zero (0.0). Dentro da estrutura
Somar de coloque o comando S = S + X. Ao sai do laço o valor de S é a
soma dos valores de X.
Média É uma combinação de Contar com Somar, a sair da estrutura de
Programação Básica com Linguagem C 100

repetição, divida S por n para obter a média


Crie a variável Xmin, com o maior valor inicial possível. Dentro da
estrutura de repetição, coloque o comando if( Xmin > X ) Xmin =
Mínimo
X;. Ao sair da estrutura, o valor de Xmin é o valor mínimo dentre
as ocorrências da variável X.
Crie a variável Xmax, com o menor valor inicial possível. Dentro da
estrutura de repetição, coloque o comando if( Xmax < X ) Xmax =
Máximo
X;. Ao sair da estrutura, o valor de Xmax é o valor máximo dentre
as ocorrências da variável X.
Crie as variáveis inteiras Nt para contar todas as ocorrências e Ni
para contar as ocorrências de interesse, ambas com valor inicial
zero (0). Dentro da estrutura de repetição, coloque o comando
Percentagens Nt++ para contar todas as ocorrências e o comando if para contar
as ocorrências de interesse e executar Ni++. Ao sair da estrutura
de repetição, a razão 100*double(Ni)/Nt é a percentagem das
ocorrências de interesse.
Observe que, para obter o mínimo, deve–se iniciar com o "maior valor possível"
e o operador relacional é "maior do que".
Por outro lado, para obter o máximo, deve–se iniciar com o "menor valor
possível" e o operador relacional é "menor do que".
O resultado de percentagens deve ser double pois são esperados valores
fracionários. Como 100*Ni/Nt é uma razão entre inteiros, o comando double(Ni)
evita arredondamentos. Para imprimir 100*double(Ni)/Nt é necessário o formato %f,
assim:

printf( " percentagem %lf %%", 100*double(Ni)/Nt );

O duplo %% imprime o símbolo de percentagem uma única vez.

Outro Algoritmo para o Mínimo


Crie a variável Xmin. Dentro da estrutura de repetição, coloque os
comandos if( contador == 0 ) Xmin = X; e if( Xmin > X ) Xmin = X. Ao
sair da estrutura, o valor de Xmin é o valor mínimo dentre as
ocorrências da variável X.
Programação Básica com Linguagem C 101

(a) (b)
Figura 4.14 Fluxograma para: a) contar de 0 até N–1; b) somar N–1 valores lidos e
imprimir o resultado.

Exemplo 4.40 Foram obtidas as idades de 7 crianças. Faça um programa em C


para ler e calcular os valores mínimo, máximo e média destas idades. Imprima os
valores calculados.
Dos dados de entrada são valores de idade – seja idade o nome desta variável, o
tipo int é suficiente ela.
Dos dados de saída são a idade média, a idade mínima e a idade máxima.
Para calcular a média é necessário contar as ocorrências de idade e somá–las. De
antemão já seu a contagem mas vou contar assim mesmo a título de exemplo.
Seja S a variável a ser utilizada para somar, o tipo float é sempre o melhor tipo
para soma. Seja n a variável a ser utilizada para contar, o tipo int é sempre o
melhor tipo para contador. Tanto S quanto n devem receber zero inicialmente.
Para obter a idade mínima, será usada a variável Imin, do tipo int – mesmo de
idade – e terá valor inicial igual a 1000 porque é uma idade que ninguém por ora.
Para obter a idade máxima, será usada a variável Imax, do tipo int – mesmo de
idade – e terá valor inicial igual a 0 porque é a menor idade possível.
Programação Básica com Linguagem C 102

Será necessário declarar o int c para contador do laço for e também a constante
MAX com valor 7, número de idade medidas que deverão ser lidas no laço for.
Dentro do laço for serão colocados os comandos conforme a Tabela 4.17.
Ao sair do laço for, serão impressos os valores Imin, Imax e S/n, a idade média.
#include <stdio.h>
#define MAX 7
int main( void ){
int idade, n, Imin, Imax, c;
float S;

n = 0;
Imin = 1000;
Imax = 0;
S = 0.0;

for( c = 0; c < MAX; c++ ){


printf(" De o valor da idade: " );
scanf("%d", &idade );
n = n + 1;
S = S + idade;
if( Imin > idade ) Imin = idade;
if( Imax < idade ) Imax = idade;
}

printf( "\n menor idade: %d ", Imin );


printf( "\n maior idade: %d ", Imax );
printf( "\n idade media: %f ", S/n );

return 0;
}
Não foi atribuído um valor inicial para leitura pois seus valores são dados de
entrada para o programa.
Pode–se criar a variável float de nome m e, depois do laço for, colocar o comando
m = S/n e imprimir o valor de m.
É conveniente que valores de média sejam do tipo float pois são obtidos por meio
da operação de divisão, cujo valor esperado são números fracionários.
Observe que foi criado um pequeno dicionário com as varáveis do programa, seus
tipos e valores iniciais. E, o mais importante, a finalidade de cada uma delas, as
operações a realizar com cada uma delas e onde colocar cada comando a elas
referentes. Isso tudo antes de começar a digitar o programa de computador.
No início, o acadêmico fica um pouco confuso com estes procedimentos mas, ao
Programação Básica com Linguagem C 103

praticá–los, serão abstraídos e se tornarão boas práticas de planejamento de


programação.

(a) (b)
Figura 4.15 Fluxograma para: a) calcular a média de N–1 valores lidos e imprimir o
resultado; b) obter o máximo de N–1 valores lidos e imprimir o resultado.

Exercício 4.27 Faça x variar de –100.0 a 100.0, de 0.001 em 0.001, e verifique se


cos2x+sen2x = 1, teste para float, double e long double.

Exercício 4.28 Faça x, y e z variar de –100.0 a 100.0, de 0.001 em 0.001, e


verifique as ocorrências de z² = x2+y2, compare com os cálculos exatos da
matemática.
Programação Básica com Linguagem C 104

Aprendendo um pouco de função

Alguns exercícios abaixo possuem vários itens; neste caso, faça um


programa para cada item e, ao final, faça um outro programa para
juntar tudo onde os itens organizados como funções. Segue um
exemplo:
#include <stdio.h>
#define MAX 7
void a( void ){ código do item a }
void b( void ){ código do item b }
void c( void ){ código do item c }
...
int main( void ){
a();
b();
c();
...
return 0;
}
Agrupar códigos em funções é uma forma de organizar programas.

4.7.3. Exercícios

1. Faça um programa para ler imprima N = 22 vezes a frase "Alo mundo!" usando
estrutura sequencial e a estrutura de repetição for. Como seria este programa se N =
222?
2. Faça um programa para ler um número inteiro positivo e informar se ele é triangular.
Um número natural n é triangular se é igual à soma dos k primeiros números
naturais consecutivos, a partir de 1. Por exemplo, 10 = 1 + 2 + 3 + 4 é triangular.
3. Foi feita uma estatística de cinco turmas de Linguagem C, da Univasf, para verificar a
aprendizagem dos estudantes. Foram obtidos os seguintes dados:

• código da turma
• número de estudantes por turma
• número de estudantes com nota maior do que 7.0

Deseja–se saber:
a) qual é a média das notas, das cinco turmas juntas
b) qual é a média das notas menores ou iguais a 7.0, das cinco turmas juntas
c) qual é a média das notas maiores do que 7.0, de cada turma
4. Faça um programa que receba duas notas de seis estudantes da Univasf. Calcule e
mostre:
a) a média de cada estudante
Programação Básica com Linguagem C 105

a) o percentual de estudantes aprovados


a) o percentual de estudantes de exame
a) o percentual de estudantes reprovados;
b) a média da classe.
5. Foi feita uma pesquisa para determinar o índice de aprovação de estudantes da
Univasf em dado período. Faça um programa que:

• leia o número de estudantes matriculados no período


• leia a nota cada estudante matriculado e identifique seu sexo

O programa deve calcular e mostrar:


a) a percentagem de estudantes aprovadas no período e do sexo feminino
b) a percentagem de estudantes aprovados no período e do sexo masculino
c) a percentagem de estudantes que tiveram nota menor do que 5
6. Faça um programa que receba um número, calcule e mostre a tabuada desse
número.
7. Faça um programa que mostre as tabuadas dos números de 1 a 10. Com dois tipos
de saída:
a) impressas uma abaixo da outra
b) dispostas lado a lado.
8. Um funcionário de uma empresa recebe aumento salarial anualmente. Faça um
programa que determine o salário atual desse funcionário sabendo que:
a) esse funcionário foi contratado em 2010, com salário inicial de R$ 5.000,00.
b) em 2011, ele recebeu aumento de 1,5% sobre seu salário inicial.
c) a partir de 2012 (inclusive), os aumentos salariais sempre corresponderam ao
dobro do percentual do ano anterior.
9. Faça um programa que leia um número de termos, determine e mostre os valores de
acordo com a série 2, 7, 3, 4, 21, 12, 8, 63, 48, 16, 189, 192, 32, 567, 768 …
10.Em uma fábrica trabalham 15 operários, homens e mulheres divididos em três
classes:

• trabalhadores que fazem até 30 peças por mês — classe 1


• trabalhadores que fazem de 31 a 50 peças por mês — classe 2
• trabalhadores que fazem mais de 50 peças por mês — classe 3

A classe 1 recebe o salário–mínimo. A classe 2 recebe o salário–mínimo mais 2%


deste salário por peça, acima das 30 das peças iniciais. A classe 3 recebe o salário–
mínimo mais 3% desse salário por peça, acima das 30 peças iniciais. Faça um programa
que receba o código do operário, o número de peças fabricadas no mês, o sexo do
operário, e que também calcule e mostre:
a) o código do operário e seu salário;
b) o total da folha de pagamento da fábrica;
c) o número total de peças fabricadas no mês;
d) a média de peças fabricadas pelos homens;
e) a média de peças fabricadas pelas mulheres; e
f) o código do operário de maior salário, seu salário e se é homem ou mulher.
11.Faça um programa que calcule o saldo de uma conta bancária tendo como entrada o
Programação Básica com Linguagem C 106

saldo inicial e dez lançamentos de operações de crédito e/ou débito. A saída são o
total de créditos, o total de débitos, os juros pagos ao banco (5% do total de débitos)
e o saldo final.
12.Execute este programa e explique seu comportamento.

#include <stdio.h>
int main ( void ){
char c;
for( c = 0; c < 300; c++ ){
if( c % 16 == 0 ) printf("\n");
printf(" %+3c ", c );
}
return 0;
}

13.Execute este programa e explique seu comportamento.

#include <stdio.h>
int main ( void ){
int i;
for( i = 0; i < 120; i++ ){
if( i % 16 == 0 ) printf("\n");
printf(" %+3c ", i );
}
return 0;
}

Exercício 4.29 Imprima os seguintes padrões em stdout:

* * ************* ************* 1 2 3 4 5 6 7
** *** * * 2 3 4 5 6 7
*** ***** ************* ************* 3 4 5 6 7
**** ******* * * * 4 5 6 7
***** ********* ************* ************* 5 6 7
****** *********** * * * 5 6
******* ************* ************* ************* 6
(a) (b) (c) (d) (e)

7 # # # # # # # | # # # # # # # 7 | 7
7 6 # # # # # # | # # # # # # 7 6 | 6 7
7 6 5 # # # # # | # # # # # 7 6 5 | 5 6 7
7 6 5 4 # # # # | # # # # 7 6 5 4 | 4 5 6 7
7 6 5 4 3 # # # | # # # 7 6 5 4 3 | 3 4 5 6 7
7 6 5 4 3 2 # # | # # 7 6 5 4 3 2 | 2 3 4 5 6 7
7 6 5 4 3 2 1 # | # 7 6 5 4 3 2 1 | 1 2 3 4 5 6 7
(f) (g) (h)
Programação Básica com Linguagem C 107

4.7.4. Comando while

while – estrutura de repetição que testa sua condição e executa seu


bloco de comandos se seu valor é true.

O laço while é uma estrutura de repetição muito utilizada nos programas C. Ele
deve se usado sempre que não se souber de antemão quantas vezes o bloco de
comandos deverá ser executado. O laço while repetirá seu bloco de comando
enquanto uma condição for verdadeira.
Este laço possui:

1. uma condição manter (true) ou finalizar (false) o laço


2. um bloco de comandos

Inicialmente, o laço avalia condição de parada, se a condição for VERDADE ele


executa o bloco de comandos, caso contrário encerra o laço – o bloco é ignorado.
Sua sintaxe é:

while( condição ){
comando;
...
comando;
}

onde:

1. a condição booleana ( true ou false)


2. o bloco de comando

Observe que, para que seja possível fazer o teste, a variável de controle deve
ter sido declarada e inicializada previamente pois o teste da condição ocorre no
início do laço.

Figura 4.16 Fluxograma da estrutura de repetição while.


Programação Básica com Linguagem C 108

A condição de parada pode ser uma expressão lógica, cujo resultado deve ser
FALSO ou VERDADEIRO. Nestes casos, as variáveis que compões a expressão usada
como condição de parada devem ter sido declaradas e inicializadas previamente
pois o teste da condição ocorre logo no início do laço.
Enquanto a condição permanecer VERDADE o laço while executará seu laço. De
alguma forma, o bloco deve mudar a condição de VERDADE para FALSO para que o
laço while seja encerrado.

Exemplo 4.41 Estrutura de repetição while para contar de 0 a 4.


#include <stdio.h>
int main( void ){
int contador = 0;
while( contador < 5 ){
printf(" %d ", contador );
contador++
}
return 0;
}
O programa é inciado pela função main. Nela é declarada uma variável int
contador, para ser usada como condição de parada, logo é necessário de atribuir
um valor inicial para esta variável, no caso este valor é 0.
O programa executa o laço while em seguida.
O laço while testa sua condição de parada, ou seja, contador < 5? O valor inicial da
condição de parada 1 < 5 é VERDADE, logo o bloco é executado. O bloco possui
dois comandos, imprimir o valor do contador na tela e incrementar o contador
(para que em alguma repetição sua condição se torne FALSO.
O laço executa o bloco – imprime 0 na tela e incrementa o contador, o novo valor
da variável contador é 1.
O laço while testa a condição de parada. A condição 1 < 5 é VERDADE. O laço
executa o bloco – imprime 2 na tela e incrementa o contador, contador = 2.
O laço while testa a condição de parada. A condição 2 < 5 é VERDADE. O laço
executa o bloco – imprime 3 na tela e incrementa o contador, contador = 3.
O laço while testa a condição de parada. A condição 3 < 5 é VERDADE. O laço
executa o bloco – imprime 4 na tela e incrementa o contador, contador = 4.
O laço while testa a condição de parada. A condição 4 < 5 é VERDADE. O laço
executa o bloco – imprime 4 na tela e incrementa o contador, contador = 5.
O laço while testa a condição de parada. A condição 5 < 5 é FALSA. O laço é
encerrado.
Após encerrar o laço, o programa retorna 0 e também encerrado.
O laço while foi executado 5 vezes, imprimindo os números inteiros de 0 a 4 na
saída padrão.
Programação Básica com Linguagem C 109

Exemplo 4.42 Estrutura de repetição while com condição lida do teclado – ler e
imprimir números inteiros positivos lidos do teclado, o valor 0 (zero) encerra as
leituras.
Números inteiros devem ser lidos do teclado e impressos na tela enquanto seus
valores forem diferentes de zero.
O programa é resolvido com o laço while pois não se sabe o número de repetições
a serem feitas.
A condição de parada é dada pelo usuário.
O algoritmo é simples, inicialmente o primeiro número deve ser lido do teclado,
antes de entrar no laço.
O algoritmo entra no laço e verifica se o valor do número é igual a 0. Se for encerra
e nada é impresso. O programa é encerrado.
Se o primeiro valor lido é diferente de 0, o programa entra no laço, imprime o valor
do número na tela. Lê um novo valor do teclado e testa a condição. O laço while
será repetido indefinidamente até que o valor lido seja 0.
Observe que a condição de parada do while utiliza o valor lido do teclado e, por
isso, são necessário dois comandos de leitura. O primeiro, antes do laço while,
para que ele tenha com o que testar sua condição de parada. O segundo, dentro
do laço while, para que ele atualize o valor lido porque senão ele entra em loop –
laço eterno.
#include <stdio.h>
int main( void ){
int numero;

printf("\n Digite um número inteiro positivo – 0 encerra " );


scanf("%d", &numero );

while( contador == 0 ){
printf("\n O numero digitado foi %d ", numero );
printf("\n Digite um número inteiro positivo " );
scanf("%d", &numero );
}
return 0;
}

A estrutura de repetição while é executada zero vezes ou mais.


Programação Básica com Linguagem C 110

4.7.5. Condições de Parada


A Tabela 4.18 contém as condições de parada calculadas e lidas pelo teclado e
seus algoritmos.

Tabela 4.18 Condição calculada e lida pelo teclado e seus algoritmos


Condição Procedimento
cria–se uma variável para controlar o laço while antes dele. Atribui–se a ela
um valor tal que, ao ser testado no laço while, seja VERDADE, caso contrário
o laço não será executado. Dentro do laço while, o valor da variável deve,
Calculada
em alguma repetição, ser alterado de modo que, ao ser avaliada pela
condição do laço ela seja FALSO, encerrando o ciclo de repetição. Leia
atentamente os Exemplo 4.43 e Exemplo 4.44.
cria–se uma variável para controlar o laço while antes dele. Antes de entrar
no laço while o valor da variável deve ser lida do teclado. Após esta primeira
leitura já se pode entrar no laço while. Ao ser testado no laço while, se a
Lida pelo condição for VERDADE o laço será executado, caso contrário o laço não será
teclado executado. Dentro do laço while o valor da variável deve ser lida do teclado
e seu valor, em alguma repetição, ser tal que, ao ser avaliada pela condição
do laço ela seja FALSO, encerrando o ciclo de repetição. Leia atentamente o
Exemplo 4.45.

Exemplo 4.43 Somar os números naturais, sequencialmente, de 1 até que o total


ultrapasse 100.
#include <stdio.h>
int main( void ){
int numero, conta, Soma;

numero = 0;
conta = 0;
Soma = 0;

while( Soma <= 100 ){


numero = numero + 1;
conta = conta + 1;
Soma = Soma + numero;
}
printf("\n Soma dos números = %d ", Soma );
printf("\n Quantidade de numeros = %d ", conta );
printf("\n Ultimo numero somado = %d ", numero );

return 0;
}
Programação Básica com Linguagem C 111

Exemplo 4.44 Somar números inteiros e positivos lidos pelo teclado enquanto o
total for menor do que 100.
#include <stdio.h>
int main( void ){
int numero, conta, Soma;

conta = 0;
Soma = 0;

while( Soma < 100 ){


printf("\n Digite um numero inteiro positivo " );
scanf("%d", &numero );
conta = conta + 1;
Soma = Soma + numero;
}
printf("\n Soma dos números = %d ", Soma );
printf("\n Quantidade de numeros = %d ", conta );
printf("\n Ultimo numero lido = %d ", numero );

return 0;
}

Exemplo 4.45 Calcule a soma de números inteiros e positivos lidos pelo teclado.
#include <stdio.h>
int main( void ){

int numero, conta, Soma;

conta = 0;
Soma = 0;

printf("Digite um número inteiro positivo – 0 encerra " );


scanf("%d", &numero );

while( numero != 0 ){
conta = conta + 1;
Soma = Soma + numero;

printf("\n Digite um número inteiro positivo " );


scanf("%d", &numero );
Programação Básica com Linguagem C 112

printf("\n Soma dos números = %d ", Soma );


printf("\n Quantidade de numeros = %d ", conta );

return 0;
}

Estude o Capítulo 3 – Comando e Controle do Programa.

4.7.6. Exercícios

1. Faça um programa que leia um conjunto não determinado de valores e mostre o


valor lido, seu quadrado, seu cubo e sua raiz quadrada. Finalize a entrada de dados
com um valor negativo ou zero.
2. Somar os números naturais de 1 até que o total seja menor do que 100.
3. Faça um programa que receba o salário de um funcionário chamado Carlos. Sabe–se
que outro funcionário, João, tem salário equivalente a um terço do salário de Carlos.
Carlos aplicará seu salário integralmente em um fundo que rende 2% ao mês, e João
aplicará seu salário integralmente em um outro fundo que rende 3% ao mês. O
programa deverá calcular e mostrar a quantidade de meses necessários para que o
montante de João iguale ou ultrapasse o montante de Carlos.
4. Faça um programa que leia um número não determinado de pares de valores [m,n],
todos inteiros e positivos, um par de cada vez, e que calcule e mostre a soma de
todos os números inteiros entre m e n (inclusive). A digitação de pares terminará
quando m for maior ou igual a n.
5. Faça um programa para ler o código, o sexo e o número de horas/aula dadas
mensalmente pelos professores de uma universidade, sabendo–se que cada
hora/aula vale R$ 70,00. Emita uma listagem contendo o código, o salário bruto e o
salário líquido (desconto de 10% para homens e de 5% para mulheres) de cada
professor. Mostre também a média dos salários líquidos dos professores do sexo
masculino e a média dos salários líquidos dos professores do sexo feminino. As
informações terminarão quando for lido o código 99999.
6. Faça um programa que receba vários números inteiros, calcule e mostre:
a) a soma dos números digitados
b) a quantidade de números digitados
c) a média dos números digitados
d) o maior número digitado
e) o menor número digitado
Programação Básica com Linguagem C 113

f) a média dos números pares


g) a porcentagem dos números ímpares entre todos os números digitados
7. Faça um programa que receba uma senha numérica e verifique se a senha está
correta e, caso não esteja, solicite novamente a senha. O programa deve informar
"Senha Correta", "Senha Incorreta" e, após, 10 tentativas, "Acesso Bloqueado".
8. A sequência de Fibonacci é dada por F = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
233, 377, 610, 987, 1597, 2584, 4181, 6765, … }, cuja função geradora é F(n).
Escreva uma função para imprimir em stdout o valor de n tal que F(n) > 1234567.
9. Escreva um programa para calcular o maior valor da sequência de Fibonacci
utilizando variáveis do tipo: a) unsigned char, b) unsigned short int, c) unsigned int,
d) unsigned long int, f) float, g) double e h) long double.
10.Escreva um programa para calcular o maior valor do fatorial utilizando variáveis do
tipo: a) unsigned char, b) unsigned short int, c) unsigned int, e) unsigned long int, f)
float, g) double e h) long double.
11.Uma empresa decidiu fazer um levantamento em relação aos candidatos que se
apresentarem para preenchimento de vagas em seu quadro de funcionários. Faça
um programa que leia, para cada candidato, a idade, o sexo e a experiência no
serviço (com e sem experiência). Para encerrar a entrada de dados, digite zero para
a idade. O programa deve calcular e mostrar:
a) o número de candidatos do sexo feminino
b) o número de candidatos do sexo masculino
c) a idade média dos homens que já têm experiência no serviço
d) a porcentagem dos homens com mais de 45 anos entre o total dos homens
e) o número de mulheres com idade inferior a 21 anos e com experiência no serviço
f) a menor idade entre as mulheres que já têm experiência no serviço.
12.Antônio tem 1,50 m e cresce 2 cm por ano, enquanto José tem 1,10 m e cresce 3 cm
por ano. Faça um programa para calcular e imprimir quantos anos é necessário para
que José seja maior que Antônio.
13.Dois automóveis estão distantes 80 km um do outro em uma grande reta. Se um vai
em direção ao outro com velocidades de 50 e 60 km/h, faça um programa para
calcular onde e quanto tempo demoram para se encontrarem.
14.Um canhão com ângulo de 50°, atira um projétil com velocidade de 300 km/h. Se o
vento diminui o seu alcance de 2 m a cada segundo, faça um programa para estimar
a que distância do canhão o projétil vai explodir.
15.Uma caixa d’água, de 1000 L está vazia, e começa a recebe água com vazão de 5
L/minuto. Faça um programa que calcule o tempo necessário para enchê–la sabendo
que é feita uma descarga de 50 L a cada 30 minutos, uma lavagem de 100 L a cada
2 horas e que tem um furo que perde água com vazão de 0,01 L/s. O que mudaria se
consertasse o furo?
16.Um relógio de pêndulo tem período T ( T =2 π √ l/ g ), sabendo que g = 9,80665
m/s², l = 17,23443 cm e que o pêndulo diminui o seu período de 0,01% a cada ano
devido ao atrito, g diminui 0,00005% por mês devido à deriva continental do lugar do
pêndulo, faça um programa para relatar perdas de período do pêndulo de 1,00000 s
usando variáveis do tipo: a) float, b) double e c) long double. Há diferenças entre os
resultados a, b e c?
17.Faça um programa que simule a urna eletrônica. A tela a ser apresentada deverá ter
Programação Básica com Linguagem C 114

ser as opções:

• Candidato 1
• Candidato 2
• Candidato 3
• Candidato 4
• Candidato 5
• Nulo
• Branco
• Entre com o seu voto:

O programa deverá ler os votos dos eleitores e, quando for lido o número 8,
apresentar as seguintes informações:
a) o número de votos de cada candidato
b) a porcentagem de votos nulos
c) a porcentagem de votos brancos
d) o candidato vencedor.

4.7.7. Comando do/while


O laço do/while é também uma estrutura de repetição da linguagem C, seu
diferencial é o teste da condição de parada ao seu final.
O bloco é executado a primeira vez e laço do/while repetirá seu bloco de
comando enquanto a condição de parada for verdadeira.
Estes tipos de repetição são semelhantes a um FOR, pois uma ou mais
instruções são executadas repetidas vezes. A diferençca é que aqui não temos um
número fixo de vezes para repetir. A repetição termina quando uma determinada
condição é verdadeira.

do/while – estrutura que executa seu bloco de comandos, testa sua


condição e repete se seu valor é true.

A condição de parada pode ser uma expressão lógica, cujo resultado deve ser
FALSO ou VERDADEIRO. Nestes casos, as variáveis que compões a expressão usada
como condição de parada devem ter sido declaradas e mas não é necessário
inicializá–las previamente pois o teste da condição ocorre no final do laço.
No algoritmo abaixo, o laço do/while é repetido indefinidamente até que seja lido
0 do teclado.

#include <stdio.h>
int main( void ){
char op;
do{
Programação Básica com Linguagem C 115

printf("\n escolha sua opcao: " );


scanf( " %c", &op );
}while( op != '0' );
return 0;
}

Observe que o laço do/while é executado ao menos uma vez, como a variável op
é lida dentro do laço é desnecessário dar um valor inicial a ela, Figura 4.18.

Figura 4.17 Fluxograma da estrutura de repetição do/while.

Figura 4.18 Fluxograma para contar de 0 até N–1 usando do/while.

Exemplo 4.46 Calculadora de quatro operações com do/while.


#include <stdio.h>

int main( void ){


char op;
do{
float a, b;
printf("\n\n\n\n" );
printf("\n Calculadora ");
Programação Básica com Linguagem C 116

printf("\n --------------- ");


printf("\n + Somar ");
printf("\n - Subtrair ");
printf("\n * Multiplicar ");
printf("\n / Dividir ");
printf("\n --------------- ");
printf("\n 0 Encerrar ");
printf("\n l limpar ");
printf("\n --------------- ");
// o espaço antes de %c é para evitar ler ENTER
printf("\n escolha sua opcao: " ); scanf( " %c", &op );
if( (op == 'l') || (op == '0') ){
system("cls || clear");
continue;
}
printf("\n digite o primeiro número: " );
scanf( "%f" , &a );
printf("\n digite o segundo número: " );
scanf( "%f" , &b );
switch( op ){
case '+': printf("\n %f + %f = %f", a, b, a+b );
break;
case '-': printf("\n %f - %f = %f", a, b, a-b );
break;
case '*': printf("\n %f * %f = %f", a, b, a*b );
break;
case '/': printf("\n %f / %f = %f", a, b, a/b );
break;
default : printf("\n :: opcao invalida :: \n");
}
}while( op != '0' );
return 0;
}

Exemplo 4.47 Fazer um programa para exibir os valores de Vout de um circuito em


malha aberta de um amplificador operacional.
O Amplificador Operacional genérico possui duas entradas e uma saída. Se a saída
é conectada à entrada inversora, após passar por um divisor de tensão, vale a
equação abaixo.
Programação Básica com Linguagem C 117

R2
1+
V out R1
=
V iin 1 R 2
+ +1
G GR 1

Em que G é o ganho em malha aberta do amplificador operacional.


Esta conexão de realimentação negativa, também chamada de configuração de
amplificador não inversor, é o uso mais comum de um amplificador operacional,
porém muitas configurações diferentes são possíveis, fazendo dele um dos mais
versáteis blocos de construção em eletrônica.
Na realimentação negativa a resposta se opõe ao estímulo, interrompendo a alça
de resposta.
int main( void ){
double Vin, Vout, G, R1, R2;
Vin = 5.0;
G = 2.6;
R1 = 500.0;
R2 = 300.0;
do{
Vout = Vin*(1.0 + R1/R2)/(1.0/G + R2/G/R1 + 1.0);
Vin -= 0.1;
printf("\n Vout = %0.3f", Vout );
}while( Vout > 3.0 );
return 0;
}

A estrutura de repetição do/while é executado uma vez ou mais.

4.7.8. Exercícios

1. Faça um programa que leia números inteiros não-nulos do teclado e calcule a soma e
Programação Básica com Linguagem C 118

subtração alternadamente destes números. Exemplo: a sequência {5, 7, 1, 4, 9}


será calculada como 5 - 7 + 1 - 4 + 9.
2. Somar os números naturais de 1 até que o total seja menor do que 100.
3. Faça um programa que leia números de stdin que número seja igual a zero. No final,
mostre a soma dos números lidos.
4. Escreva um programa financeiro com quatro opções: a) consultar saldo, (b) sacar
numerário, c) depositar numerário e d) encerrar. O saldo deve iniciar em R$ 0,00. A
cada saque ou depósito o valor do saldo deve ser informado.

4.7.9. Comandos break e continue


Os comandos break e continue alteram o fluxo de controle do laço onde se
encontra. Um laço pode conter nenhum, um ou mais comandos break. Um laço
pode conter também nenhum, um ou mais comandos continue.
O comando break encerra o laço em que está contido, como ilustrado na Figura
4.19.

Figura 4.19 Efeito do comando break nos laços de repetição for, while e do/while.

O comando continue ignora todos os comandos abaixo dele e volta ao for, while
ou do/while, como ilustrado na Figura 4.20.

Figura 4.20 Efeito do comando continue nos laços de repetição for, while e do/while.

O comando break do comando switch, comporta-se do mesmo modo


que o break dos laços de repetição (for, while e do/while). Em
qualquer um destas estruturas de comandos, ao ser executado, o
break força a saída do bloco em que se encontra, quer seja do switch,
quer seja de uma estrutura de repetição.
Se o comando break estiver dentro de um laço interno, a execução do
break encerrará o laço interno e o programa executará o próximo
comando do laço externo.
Programação Básica com Linguagem C 119

4.7.10. Resumo

Figura 4.21 Mapa mental de Estrutura.

Estude o Capítulo 3 – Comando e Controle do Programa.

4.8. Funções
Quando os programas C tornam–se maiores e mais complexos, pode–se
melhorar sua clareza e compreensão dividindo–o em partes menores, denominadas
funções.
Funções é uma forma de reutilização de código, ou seja, escreve o código
apenas uma vez e use quantas vezes for necessário. A de reutilização de código é
uma boa prática de programação pois evita retrabalho, aumentando a eficiência da
programação.

função – conjunto de comandos referenciado por um nome,


desenvolvido separadamente de outras partes do programa.

Na linguagem C, funções são os blocos de construção da linguagem, são


desenvolvidos separadamente de outras partes do programa, possuindo tipo de
dado, nome e parâmetros. Em geral, realizam tarefas específicas.
O processamento de uma função é feito da seguinte forma: ao encontrar uma
função, o programa é interrompido neste ponto e passa a executar esta função e,
ao terminar, ele retoma a execução daquele ponto em diante. Uma função pode
receber dados do programa para executar seus comandos (parâmetros ou
argumentos), e pode também retornar dados para o programa (retorno da função).
Programação Básica com Linguagem C 120

Sintaxe da função:

tipo_de_retorno NomeDaFuncao( lista_de_parametros ){


comando;
comando;

retorno_da_função ...; // caso exista
}

O tipo de retorno das funções podem ser void (a função não tem return), char,
bool, int, float, double e seus derivados. O mesmo é válido para a lista de
parâmetros formais; void indica que a função não recebe parâmetros, pode ter um
ou mais parâmetros de tipos de dados válidos, separados por vírgula. Uma função
pode receber parâmetros de diversos tipos.

Exemplo 4.48 Implementação da função SomaInt em C.


#include <stdio.h>

int SomaInt( int x, int y ){


int soma;
soma = x + y;
return soma;
}

int main( void ){


int s, a = 5, b = 7;
s = SomaInt(a,b);
printf("\n soma = %d ", s );
return 0;
}
O tipo de retorno de SomaInt é int, observe que ela retorna o valor da variável
soma que é do tipo int, esta função recebe dois parâmetros, ambos do tipo int. No
seu bloco, tem dois comandos e o return obrigatório.
A função é chamada em no programa principal, a função main, com dois
parâmetros, as variáveis a e b, ambas do tipo int.
Ao ser executado, main encontrará SomaInt, neste ponto do programa, ela
executará a função, passando os parâmetros devidos. A função SomaInt, executará
seu bloco de comando, executará o return. Neste ponto, a função main recebe o
valor retornado e atribui a s, e segue o processamento do bloco do main.
Os parâmetros da função SomaInt e seu return realiza a comunicação entre a
função SomaInt e a função main.
O fluxo de controle é feito da seguinte forma:

1. 1. O comando s = SomaInt(a,b) precisa ser avaliado, mas ele contém uma função,
Programação Básica com Linguagem C 121

logo ela deve ser avaliada primeiramente. Neste ponto o programa faz a chamada
da função SomaInt passando os argumentos (5,7).
2. 2. O fluxo de controle é transferido para a função e SomaInt e ela atribui os valores
(5,7) para seus parâmetros. Ela processa todos os seus comandos até encontrar o
comando return 12, o valor de soma.
3. 3. O fluxo de controle é transferido para o programa com o resultado 12.
4. 4. O programa substitui SomaInt pelo resultado e atribui 12 a s, ou seja, s = 12 e
passa para o próximo comando.

A utilização de funções permite dividir um programa em várias partes, cada


parte sendo uma função que realiza uma tarefa bem definida.
O fluxo de controle da chamada de funções por programas é apresentado na
Figura 4.22. A sequência deste fluxo é organizada em quatro etapas, descritas a
seguir:

1. Ao encontra uma função, o programa faz a chamada desta função passando seus
argumentos
2. O fluxo de controle é transferido para a função; ela atualiza seus parâmetros com os
argumentos recebidos e processa os seus comandos até encontrar o comando
return.
3. O fluxo de controle é transferido para o programa com o resultado do return.
4. O programa atribui o resultado ao nome da função e passa para o próximo comando.

Figura 4.22 Esquema da chamada de função pelo programa.

A Figura 4.22 representa o fluxo de controle da chamada de funções por


programas. Este raciocínio pode ser ampliado para funções chamando funções, e
assim por diante. É assim que Programa C funcionam, a função main chama várias
funções que, por sua vez, chamam várias funções que, por sua vez, chamam várias
funções … até, talvez, chegar às funções da Biblioteca Padrão.

4.8.1. Escopo de Nomes e Tempo de Vida de Variáveis


Os parâmetros das funções e as variáveis declaradas no seu bloco de comando
são chamadas variáveis locais. As variáveis locais são conhecidas apenas nas
Programação Básica com Linguagem C 122

funções que as declaram.


As variáveis globais são declaradas fora das funções, normalmente abaixo das
inclusões de bibliotecas e das constantes.

Exemplo 4.49 Implementação da função Soma em C – variáveis globais.


#include <stdio.h>

float a = 5, b = 7, R[10], S[10][10];

int Soma( void ){


int s;
s = a + b;
return s;
}
int main( void ){
printf("\n soma = %d ", Soma(a,b) );
return 0;
}
A função Soma possui uma variável local: s.
A função main, ao chamar Soma, envia void como argumento. O SO cria Soma na
Stack. Os comandos do corpo da função são executados e, ao encontrar return s, o
SO faz uma cópia do valor de s e envia para main. O SO destrói Soma e tudo a ela
relacionado. A função main recebe a cópia de s e envia para a função printf.
Vale ressaltar que as variáveis a e b podem ter seus valores alterados por Soma
pois a e b são globais.

Outra implementação para a função Soma.

Exemplo 4.50 Implementação da função Soma em C – variáveis locais.


#include <stdio.h>

float a = 5, b = 7, R[10], S[10][10];

int Soma( int x, int y ){


int s;
s = x + y;
return s;
}

int main( void ){


printf("\n soma = %d ", Soma(a,b) );
Programação Básica com Linguagem C 123

return 0;
}
As variáveis a, b, o vetor R e a matriz S são globais, são acessíveis em qualquer
lugar do programa, abaixo de suas declarações.
A função main faz uso de a e b como argumentos para a função Soma.
A função Soma possui dois parâmetros: x e y.
A função Soma possui três variáveis locais: x, y e s.
A função main, ao chamar Soma, envia os valores de a e b como argumentos. O
SO cria Soma na Stack e os parâmetros x e y para receber os valores de a e b. Os
comandos do corpo da função são executados e, ao encontrar return s, o SO faz
uma cópia do valor de s e envia para main. O SO destrói Soma e tudo a ela
relacionado. A função main recebe a cópia de s e envia para a função printf.
Vale ressaltar que os valores de a e b são podem ser alterados pela função pois ela
recebeu uma cópia dos valores de a e b. É o denominado passagem de
argumentos por valor.
A função Soma pode fazer operações com as variáveis a, b, R e S, que são globais.

argumentos – lista de variáveis que um programa envia para uma


função
parâmetros - lista de variáveis que uma função recebe de um
programa
passagem por valor – quando o valor dos argumentos é enviado de
um programa para uma função
passagem por referência - quando o endereço dos argumentos é
enviado de um programa para uma função (será visto em
apontadores)

Estude o Capítulo 6 – Funções.

4.8.2. Recursividade
Diz que uma função é recursiva quando ela chama a si mesma, direta ou
indiretamente.
Muitos problemas complexos como, por exemplo, ordenação e busca em textos, a solução
é inerente recursiva e a solução iterativa pode não existir ou ser difícil de ser encontrada.

Exemplo 4.51 As funções fat e Fib, para calcular fatorial e a série de Fibonacci,
respectivamente, são funções recursivas pois elas chamam a si mesmas.
int fat(int n){
Programação Básica com Linguagem C 124

if( n == 0 ) return 1;
else return n*fat(n–1);
}
int Fib(int n){
if( (n == 0) || (n == 1) ) return n;
else return Fib(n-2)+Fib(n-1);
}

O Exemplo 4.52 discute o consumo da Stack do programa por funções


recursivas.

Exemplo 4.52 Funções recursivas podem consumir muita memória da máquina


pois fazem uso intensivo da RAM, especificamente, da Stack do programa.

A figura ao lado representa a Stack de um


programa ao chamar a função Fib(5).
A chamada recursiva desta função usa a Stack do
programa para armazenar os valores
intermediários de Fib(4), Fib(3), Fib(2), Fib(1) e
Fib(0). Estas chamadas podem ser organizadas
em uma árvore, vista ao lado.
Foi usado Fib(5) porque é mais fácil de visualizar.
É uma fonte de erro do tipo “Estouro do Stack”,
que pode travar a máquina ou torná-la
extremamente lenta.

Uma função recursiva pode ser reescrita com o uso de iteração, e vice–versa. O
exemplo a seguir calcula a soma de um vetor de forma recursiva.

Exemplo 4.53 A soma dos elementos de um vetor de forma recursiva.


#include <stdio.h>
int Soma( int V[], int n ){
if( n > 0 ) return V[n-1]+Soma(V,n-1);
else return 0;
}
int main( void ){
int V[] = {1,2,3,4,5};
printf(" Soma = %d", Soma(V,5));
return 0;
}
Programação Básica com Linguagem C 125

Exemplo 4.54 O jogo conhecido como Torre de Hanói consiste de três torres
chamadas origem, destino e auxiliar e um conjunto de n discos de diâmetros
diferentes, colocados na torre origem na ordem decrescente dos seus diâmetros. O
objetivo do jogo e, movendo um único disco de cada vez e não podendo colocar
um disco sobre outro de diâmetro menor, transportar todos os discos para torre
destino, podendo usar a torre auxiliar como passagem intermediaria dos discos.
#include <stdio.h>

void move( char t1[10], char t2[10] ){


printf("%s --> %s \n", t1, t2);
}
void hanoi( int x, char o[10], char a[10], char d[10] ){
if( x > 0 ){
Hanoi(x-1,o,d,a);
Move(o,d);
Hanoi(x-1,a,o,d);
}
}
int main( void ){
int n;
printf("Digite o numero de discos: ");
scanf("%d", &n);
hanoi(n,"origem","auxiliar","destino");
return 0;
}

4.8.3. Recursividade x Interatividade


Como calcular Tn, soma dos pontos dos números triangulares de ordem n?
Os números triangulares são números naturais e são os obtidos através de
sucessivos triângulos equiláteros, formados pelo triângulo equilátero unitário.
O primeiro número triangular é número 1.
O segundo é o triângulo equilátero unitário, com três pontos.
O terceiro é o triângulo equilátero formado por 4 triângulos unitários, com seis
pontos.
O quarto é o triângulo equilátero formado por 9 triângulos unitários, com 10
pontos.
A série é 1, 3, 6, 10, ···, ou seja, Tn = n(n+1)/2
Programação Básica com Linguagem C 126

Os valores de Ti, podem ser escritos de duas maneiras:

Maneira 1 Maneira 2
T1 = 1 T1 = 1
T2 = 1+2 T2 = T1 + 2
T3 = 1+2+3 T3 = T2 + 3
T4 = 1+2+3+4 T4 = T3 + 4
··· ···
Tn = 1 + 2 + 3 + ··· + n-1 + n Tn = Tn-1 + n
A Maneira 1 é chamada de solução interativa, basta a última equação.
A Maneira 2 é chamada de solução recursiva, a última equação depende da
equação anterior, e assim por diante, até T1 = 1, que não tem antecedente.
Pode-se elaborar dois algoritmos, com diferentes técnicas, para resolver o
mesmo problema. A técnica interativa (Algoritmo da Maneira 1) usa a estrutura de
repetição for como solução. A técnica recursiva (Algoritmo da Maneira 2) usa a
recursividade como solução. O mesmo problema, duas soluções.

Algoritmo da Maneira 1 Algoritmo da Maneira 2


int M1( int n ){ int M2( int n ){
int i, T = 0; if( n == 1 ) return n;
for( i = 0; i <= n; i++ ) else return n + M2(n-1);
T += i; }
return T;
}

Tanto a técnica interativa quanto a recursiva fazem uso do Stack. A técnica


recursiva faz uso intensivo do Stack, como pode ser visto no Exemplo 4.52. Embora
Algoritmo não tenha concurso de beleza, meu senso estético admira uma solução
recursiva – o complexo se apresentando como simples.
O Algoritmo da Maneira 2, que usa recursividade, exige mais imaginação. E,
embora sejam apenas letras, ele é portador de uma dinâmica que lhe é própria, que
se tornará presente ao ser executado e, quem programa, deve antecipá–la em
detalhe no ato da escrita.

4.8.4. Protótipo de Função


Na linguagem C há o protótipo de uma função que serve para indicar apenas seu
cabeçalho, que é constituído pelo seu tipo, nome e parâmetros. O protótipo das
funções acima são:
Programação Básica com Linguagem C 127

void escreva( void );


int soma ( int, int );
void saida ( int, int );
void divide ( float, int );

Os protótipos indicam os tipo da função, seu nome e os tipos e quantidades de


parâmetros entre parêntesis e o delimitador ponto e vírgula.
Sabendo o protótipo de uma função é o suficiente para usá–la. Neste caso, o
corpo da função é, ou está feito, em outro lugar.

4.8.5. Resumo

Figura 4.23 Mapa mental de Função.

4.8.6. Exercícios

1. Faça uma função que receba um número inteiro e positivo N como parâmetro e
retorne a soma dos números inteiros existentes entre o número 1 e N (inclusive).
2. Crie uma função que receba três números inteiros como parâmetros, representando
horas (h), minutos (min) e segundos (s), e os converta em segundos. Exemplo: 2 h,
40 min e 10 s correspondem a 9.610 s.
3. Faça uma função que receba um valor inteiro e verifique se ele é positivo ou
negativo.
4. Crie uma função que receba como argumento a altura (h) e o sexo de uma pessoa e
retorne seu peso ideal. Para homens, deverá calcular o peso ideal usando a fórmula:
peso ideal = 72.7 h − 58; para mulheres: peso ideal = 62.1 h − 44.7.
5. Elabore uma função que leia um número não determinado de valores positivos e
retorne a média aritmética desses valores. Terminar a entrada de dados com o valor
zero.
6. Faça uma função que receba um valor inteiro e positivo, calcule e mostre seu
fatorial.
7. Elabore uma função que receba como parâmetro um valor n (inteiro e maior ou igual
a 1) e determine o valor da soma S = 1 +1/2 + 1/3 + … + 1/n.
8. Faça uma função que receba como parâmetro um valor inteiro e positivo n,
indicando a quantidade de parcelas de uma soma S, calculada pela fórmula: S = 1/3
+ 2/4 + 5/5 + 10/6 + 17/7 + 26/8 + ··· + (n2+1)/(n+3).
9. Foi realizada uma pesquisa entre 15 habitantes de uma região. Os dados coletados
Programação Básica com Linguagem C 128

de cada habitante foram: idade, sexo, salário e número de filhos. Faça uma função
que leia esses dados armazenando–os em vetores. Depois, crie funções que recebam
esses vetores como parâmetro e retornem a média de salário entre os habitantes, a
menor e a maior idade do grupo e a quantidade de mulheres com três filhos que
recebem até R$ 500,00 (utilize uma função para cada cálculo).
10.A prefeitura de uma cidade fez uma pesquisa entre seus habitantes, coletando dados
sobre o salário e o número de filhos. Faça uma única função que leia esses dados
para um número não determinado de pessoas e imprima a média de salário da
população, a média do número de filhos, o maior salário e o percentual de pessoas
com salário inferior a R$ 1.200,00.
11.Crie um programa que receba três valores (obrigatoriamente maiores que zero),
representando as medidas dos três lados de um triângulo. Todas as mensagens
deverão ser mostradas em main. Elabore funções para: a) determinar se esses lados
formam um triângulo (sabe–se que, para ser triângulo; b)a medida de um lado
qualquer deve ser inferior ou igual à soma das medidas dos outros dois). determinar
e mostrar o tipo de triângulo (equilátero, isósceles ou escaleno), caso as medidas
formem um triângulo.
12.Faça um programa que receba a temperatura média de cada mês do ano e
armazene–as em um vetor. O programa deverá calcular e mostrar a maior e a menor
temperatura do ano, junto com o mês em que elas ocorreram (o mês deverá ser
mostrado por extenso: 1 = janeiro; 2 = fevereiro; …). Observação: não se preocupe
com empates. Cada cálculo deve ser realizado e mostrado em uma função.
13.13. Crie um programa que receba o número dos 10 alunos de uma sala,
armazenando–os em um vetor, junto com as notas obtidas ao longo do semestre
(foram realizadas quatro avaliações). Elabore funções para: a) determinar e mostrar
a média aritmética de todos os alunos; b) indicar os números dos alunos que deverão
fazer recuperação, ou seja, aqueles com média inferior a 6. Todas as mensagens
deverão ser mostradas em main.
14.Encontre o elemento de maior valor gerado por uma série de Fibonacci utilizando os
tipos char, int e long. Explique estes resultados.
15.Encontre o elemento de maior valor gerado pelo fatorial tipos char, int, long, float e
double. Explique estes resultados.
16.Elabore e teste uma função recursiva para calcular o resto da divisão inteira usando
subtração.
17.Elabore e teste uma função recursiva para calcular o quociente da divisão inteira
usando subtração.
18.Elabore e teste uma função recursiva para calcular o produto de dois números
naturais usando adição.
19.Elabore e teste uma função que retorna o número de segundos de x horas.
20.Elabore e teste uma função para verificar se um ano é bissexto.
21.Elabore e teste uma função que retorna o número dias um dado mês.
22.Escreva e teste uma função que recebe dois ponteiros apontados para float e
compare os valores apontados.

4.9. Apontadores
Programação Básica com Linguagem C 129

Os apontadores ou ponteiros, é um Tipo de Dado da Linguagem C que


armazena endereços de memória e de outros itens de hardware. Variáveis
ponteiros trabalham em estreita cooperação com o Sistema Operacional e o
Hardware para acessar a memória, dentre outros componentes do computador e
suas conexões físicas.

apontador – tipo de dado cujo valor faz referência diretamente a uma


região da memória, por meio do seu endereço

Variáveis ponteiros permitem acesso físico ao hardware, controlando–os a partir


de Programas C. Elas também permitem acessar outras variáveis do programa de
forma indireta, um dos seus grandes usos.
As variáveis possuem três atributos básicos: seu nome, o valor armazenado por
ela e o endereço de memória onde ela está armazenada. Os ponteiros, em vez de
armazenar valores, armazenam endereços de memória. Ao utilizar ponteiros, pode–
se acessar endereços e manipular valores lá armazenados.
Variáveis ponteiros são muito úteis e provê grandes recursos para a Linguagem
C, seu correto entendimento e seu uso é básico para a programação porque:

a) são os meios pelos quais as funções podem modificar seus argumentos de chamada
b) gerenciam a memória de máquina via alocação dinâmica, uso de Heap
c) melhoram a eficiência de certas rotinas
d) fornecem suporte para estruturas dinâmicas de dados
e) manipulam o sistema de arquivos
f) permitem acesso ao hardware, local ou remoto

Os ponteiros são ótimos recursos e um dos grandes diferencias da Linguagem C.


Dentre suas aplicações seguem algumas muito úteis:

• a transmissão de uma grande quantidade de dados a outra parte do programa pode


ser feita fazendo uma cópia destes dados (consome tempo e recursos) ou enviando o
endereço destes dados, seu apontador, apenas um valor.
• o conceito de apontadores se aplica a funções C, pode-se passar apontadores como
argumentos de funções (passagem por referência), funções podem retornar
apontadores e pode-se, ainda, criar apontadores para funções
• uma função C pode devolver apenas um valor com o comando return mas, uma
função pode receber um apontador para uma região da memória, fazer operações
nela e retornar um apontador para essa mesma região ou outra região da memória.
Isto será feito, usando variáveis estruturadas como strings, vetores, matrizes,
arquivos e struct em geral
• apontadores de apontadores, ou indireção múltipla, tem muitas aplicações em
algoritmos de busca e ordenação de listas, pilhas, árvores e grafos
• o acesso ao Heap, uma parte da Pilha de Chamada C, é feita exclusivamente por
apontadores, que permite manipular grandes regiões da memória da máquina
Programação Básica com Linguagem C 130

• o acesso a qualquer item de hardware é feito exclusivamente por apontadores, que


permite sua manipulação e controle

4.9.1. Ponteiro
As variáveis ponteiro ou apontadores são utilizadas para acessar hardware,
estas variáveis armazenam endereços de dispositivos físicos como, por exemplo,
memória, impressora, placa de rede. Os ponteiros são variáveis especializadas, elas
estão relacionadas aos seus tipos de declaração, portanto temos ponteiros para
todos os tipos, como char, int, float, double.
Os ponteiros são utilizados, principalmente, para:

a) alocação dinâmica de memória


b) manipulação de strings, vetores e matrizes
c) em funções
d) referência para listas, pilhas, árvores e grafos

Sintaxe de declaração de ponteiro:

tipo *NomePonteiro;

sendo:

a) tipo* – declara um ponteiro capaz de armazenar endereços;


b) tipo – tipo de variável cujo endereço o ponteiro armazena
c) NomePonteiro – nome da variável ponteiro.

O asterisco * nesta de declaração indica que a variável é um ponteiro.

Figura 4.24 Relação entre apontador e variável.

Exemplo 4.55 Declaração de variáveis e ponteiros.


#include <stdio.h>
int main( void ){
char *pc;
int *pi;
long *pli;
float *pf;
Programação Básica com Linguagem C 131

double *pd;
long double *pld;
return 0;
}
Este código declara seis variáveis ponteiros, um ponteiro para cada tipo.
Numa declaração, o asterisco antecedendo o nome da variável indica que a
mesma é um ponteiro, trata–se de variáveis para armazenar endereços, não
podem armazenar valores.
Os ponteiros para variáveis tipo char, no caso pc – ponteiro char, são específicos
para variáveis tipo char. Não podem ser usados para apontar para variável de
outro tipo, serve apenas para variáveis tipo char.
O mesmo vale para os demais ponteiros.

Exemplo 4.56 Declaração de variáveis e ponteiros e variáveis convencionais.


#include <stdio.h>
int main( void ){
char *pc , ch1, ch2;
int *pi , i1 , i2 ;
long int *pli, li1, li2;
float *pf , f1 , f2 ;
double *pd , d1 , d2 ;
long double *pld, ld1, ld2;
return 0;
}
Foram declarados um ponteiro e duas variáveis de cada tipo.
Numa declaração, a presença do asterisco antecedendo o nome da variável indica
que ela armazena endereços de memória. Por outro lado, a ausência do asterisco
antecedendo o nome da variável indica ela armazenar valores.
Este código declara 18 variáveis, seis ponteiros e 12 variáveis.
As variáveis ch1 e ch2 armazenam valores do tipo char, já o ponteiro pc armazena
endereços de variáveis do tipo char, ou seja, aponta para variáveis do tipo char.
O ponteiro pc pode apontar para ch1 e ch2, não ao mesmo tempo. Quando pc
aponta para ch1, por exemplo, através de pc pode–se alterar os valores de ch1 de
forma indireta.
O ponteiro pc deve apontar apenas para tipo char, não deve ser usado para
apontar para endereços de variáveis de outros tipos.
Um ponteiro é específico para seu tipo de dado, podendo apontar para qualquer
variável deste tipo, não simultaneamente, uma de cada vez.
O mesmo pode–se afirmar para os demais ponteiros.

O tamanho em bytes dos tipos ponteiros depende da arquitetura da máquina.


Programação Básica com Linguagem C 132

Exemplo 4.57 Declaração de variáveis e ponteiros.


#include <stdio.h>
int main( void ){
printf("\n ----------------------------------");
printf("\n x sizeof(x) sizeof(*x) ");
printf("\n ----------------------------------");
printf("\n char %2d %2d", sizeof( char ), sizeof( char*) );
printf("\n int %2d %2d", sizeof( int ), sizeof( int*) );
printf("\n long %2d %2d", sizeof( long ), sizeof( long*) );
printf("\n float %2d %2d", sizeof( float ), sizeof( float*) );
printf("\n double %2d %2d", sizeof( double ), sizeof( double*) );
printf("\n long double %2d %2d", sizeof( long double), sizeof(long double*) );
printf("\n\n\n");
return 0;
}

4.9.2. Ponteiros – Endereço x Valor


A Linguagem C possui dois operadores para ponteiros, Figura 4.25:

1. * – utilizado para declarar ponteiro e para extrair valor de ponteiro


2. & – utilizado para extrair endereço de variável

Figura 4.25 Relação entre apontadores (p) e variáveis (v) em expressões.

O asterisco (*) tem dois usos e seu significado depende do contexto. No código
abaixo:

int *p, n = 10, m = 20;


Programação Básica com Linguagem C 133

p = &n;
m = *p;

Observe que o asterisco ocorre em duas condições, na declaração e na


expressão. O uso de asterisco em declarações deve ser interpretado como tal. Por
outro lado, o uso de asterisco em expressões deve interpretado como a operação
de extrair valor.

Tabela 4.19 Resumo das operações com ponteiro e variável


Comando Significado
int *p, m = 10, n = 20; Declara ponteiro para int (p), variáveis m e n do tipo int, atribui 10 a m e
20 a n.
O programa executável alocará memória RAM para m e para n, as
variáveis m e n, portanto, possui um endereço na memória do
computador.
p = &m; O operador & extrai o endereço de memória de m, previamente alocado.
A partir daí p aponta para m.
n = *p; O operador * extrai o valor do endereço de memória apontado por p e
atribui a m.
Como p aponta para m, o valor extraído é 10 e, portanto, 10 é atribuído a
n.
A partir daí n é igual a 10 e p continua apontado para m.

Tabela 4.20 Operações básicas com ponteiro e variável


Expressão Significado
Ponteiro = &Variável Ponteiro recebe endereço de Variável
*Ponteiro = Variável Variável apontado por Ponteiro recebe valor de Variável
Ponteiro = Ponteiro Ponteiro recebe Ponteiro
*Ponteiro = *Ponteiro Variável apontada por Ponteiro recebe valor de Variável apontado por Ponteiro
Variável = *Ponteiro Variável recebe valor de Variável apontado por Ponteiro

Exemplo 4.58 Operações com Ponteiro e Variável


#include <stdio.h>
int main( void ){
int *p1, *p2, *p3, v1, v2, v3;
v1 = 1;
v2 = 2;
v3 = 3;
p1 = &v1; // p1 aponta para v1
p2 = &v2; // p2 aponta para v2
p3 = &v3; // p3 aponta para v3

*p1 = 10; // p1 aponta para v1 que agora é igual 10


p1 = p2; // p1 aponta para p2 que aponta para v2
*p1 = *p3; // v2 recebe valor de v3
v1 = *p3; // v1 recebe valor de v3
Programação Básica com Linguagem C 134

*p3 = *p1 + *p2;

return 0;
}

4.9.3. Aritmética com Ponteiros


As operações com ponteiros são adição(+) e subtração(–) de inteiros.

Exemplo 4.59 Adição e subtração de ponteiro.


#include <stdio.h>
int main( void ){
int *p, i;
p = &i;

printf("\n p = %p", p );
printf("\n p++ = %p", ++p );
printf("\n p-- = %p", --p );
printf("\n p+3 = %p", p+3 );
printf("\n p-3 = %p", p-3 );

return 0;
}

Os resultados com operações envolvendo ponteiros não podem ser negativos e


nem maiores do que os limites do hardware (memória RAM em geral), se tal ocorrer
tem–se o transbordamento de dados, resultados de operações menores do que o
limite inferior permitido ou maiores do que o limite superior permitido.

4.9.4. O conceito de NULL


Como toda variável, os ponteiros também precisa possuir valores iniciais quando
necessário. O valor NULL é usado para evitar problemas com o uso de ponteiros
não inicializados com um endereço válido, sua definição é:

#define NULL (void *)0

O comando a seguir cria o apontador p para tipo unsigned long e atribui–lhe


NULL:

unsigned long *p = NULL;

4.9.5. Comparação de Ponteiros


Programação Básica com Linguagem C 135

Pode–se comparar dois ponteiros em uma expressão relacional. Por exemplo,


dados os ponteiros p e q, a seguinte declaração é válida:

if( p < q ) puts("p aponta para uma memória menor que q");

Geralmente, as comparações de ponteiros são úteis apenas quando dois ou mais


ponteiros são apontando para um objeto comum, como um vetor.
A declaração verifica se a operação envolvendo o ponteiro p foi mal sucedida e
encerra o programa:

if( p == NULL ) exit(1);

4.9.6. Ponteiro para Ponteiros


Pode–se ter um ponteiro que aponte para um outro ponteiro, esta técnica de
ponteiros para ponteiros é também denominada Indireção Múltipla. Neste caso, a
declaração é da forma:

tipo **ptr;

Essa declaração cria um ponteiro de nome ptr, o qual poderá apontar para outro
ponteiro que, por sua vez pode apontar para uma variável do tipo declarado. A
Figura 4.26 é uma representação gráfica da indireção simples e múltipla, no caso
dupla indireção.

Figura 4.26 Representação gráfica da indireção simples e múltipla.

Por exemplo:

int i, *p1, **p2;

Nesta declaração temos i – variável int, p1 – ponteiro de variável int e p2 –


ponteiro de ponteiro de variável int. São comandos válidos:

p1 = &i;
p2 = p1;

São comandos inválidos:

p2 = &i;
p1 = p2;
Programação Básica com Linguagem C 136

4.9.7. Cuidado com os Apontadores!


Os apontadores são poderosas ferramentas da Linguagem C mas devem ser
usados com muita cuidado. Se um apontador for inválido, coisas inesperadas
podem ocorrer. Diz-se que um apontador é inválido quando ele aponta para uma
posição de memória que não é uma variável do seu programa. Isso costuma ocorrer
nas seguintes situações:

• o apontador não recebeu um valor inicial, de modo que não se sabe o lugar da
memória para o qual ele aponta
• o apontador recebeu um endereço que não pertence ao seu programa, uma
atribuição com valor errado
• o apontador recebe um endereço inválido da memória, apesar de ter sido inicializado
corretamente

4.9.8. Resumo

Figura 4.27 Mapa mental de Apontador.

Estude o Capítulo 5 – Ponteiros.

4.9.9. Exercícios
Programação Básica com Linguagem C 137

1. Sejam as declarações gerais tipo *p1, *p2, *p3, *p4; e tipo v1 = 1, v2 = 2, v3 = 3, v4


= 4; Explique se as operações abaixo são válidas e quais os valores de v1, v2, v3 e
v4:
a) *p4 = *p2 + *p3 - *p1;
b) p1 = &p3;
c) v2 = p1;
d) p2 = *p3;
2. Porque a função scanf requer o uso de &?
3. Sejam as declarações gerais char *pc; int *pi; float *pf; corrija os erros das operações
abaixo se necessário:
a) *pc = ‘x‘; printf("%d", *pc);
b) *pi = 10; printf("%d" , *pi);
c) *pf = 50; printf("%f" , pf);
d) pf = pi;
e) pf = *pc;
f) *pf = *pi;
g) scanf("%c", pc);
4. Pesquise da web o conceito de dump de memória e suas aplicações.
5. Porque este código funciona?

#include <stdio.h>
int main( void ){
int n, *pi = &n;
printf("\n de o valor de int n: " );
scanf("%d", pi);
printf("\n n = %d", n );
return 0;
}

6. Escreva três comandos inválidos envolvendo ponteiro e variáveis, justificando estes


erros?
7. Explique os resultados da execução deste programa:

#include <stdio.h>
int main( void ){
char c, *pc = &c;
int i, *pi = &i;
long l, *pl = &l;
float f, *pf = &f;
double d, *pd = &d;
printf("\n\n");
printf("\n endereco pc = %p", pc );
printf("\n endereco pi = %p", pi );
printf("\n endereco pl = %p", pl );
printf("\n endereco pf = %p", pf );
printf("\n endereco pd = %p", pd );
Programação Básica com Linguagem C 138

printf("\n\n");
return 0;
}

4.10. Dados Estruturados


Os tipos simples são assim chamados por não possuir estrutura interna. Os
vetores, matrizes e strings são exemplos de dados com estrutura interna, mas são
homogêneos, admitem um único tipos.
Os dados estruturados são heterogêneos, compostos por variáveis de diferentes
tipos, é um tipo de dado padronizado mas versátil que permite representar dados
do mundo com maior fidelidade.
Dados estruturados materializa na Linguagem C a ideia de tudo em um.

A linguagem C fornece cinco maneiras de criar um tipo de dados personalizado:

a) estrutura - um agrupamento de variáveis com um nome e é chamada de tipo de


dados compostos, também é chamada de registro
b) campo de bits - uma variação da estrutura e permite fácil acesso a bits individuais
c) união - permite que a mesma região da memória seja definido como dois ou mais
tipos mais diferentes de variáveis
d) enumeração - uma lista de constantes inteiras nomeadas
e) typedef - define um novo nome para um tipo existente.

4.10.1. Vetores
O vetor é uma estrutura de dados linear que necessita de somente um índice
para que seus elementos sejam endereçados. É utilizado para armazenar uma lista
de valores do mesmo tipo, ou seja, o tipo vetor permite armazenar mais de um
valor em uma mesma variável.

vetor – lista indexada de valores do mesmo tipo de dado

Vetores são definidos como tendo um número fixo de células idênticas (seu
conteúdo é dividido em posições). Cada célula armazena um e somente um dos
valores do vetor. Cada uma das células de um vetor possui seu próprio endereço,
ou índice, através do qual pode ser referenciada. Nessa estrutura, todos os
Programação Básica com Linguagem C 139

elementos são do mesmo tipo, e cada um pode receber um valor diferente, Figura
4.28.

Figura 4.28 Representação de um vetor e seus elementos.

Algumas características do tipo vetor:

• Alocação estática (deve–se conhecer as dimensões da estrutura no momento da


declaração)
• Estrutura homogênea (armazenam de valores de mesmo tipo)
• Alocação sequencial (bytes contíguos na memória)
• Operações relacionadas ao tipo de dados armazenado

A partir do endereço do primeiro elemento é possível determinar a localização


dos demais elementos do vetor. Isso é possível porque os elementos do vetor estão
dispostos na memória um ao lado do outro e cada elemento tem o seu tamanho
fixo.
Os vetores são muito utilizadas para a resolução de problemas que envolvem
dados de um grupo homogêneo, como notas de uma classe, nomes de uma turma,
idade de uma amostra. Tem grande aplicação em Engenharia.
Para criar um vetor são necessário três atributos, a saber: o tipo de dado que vai
ser armazenado nele, seu nome e o número de elementos que possui.
A declaração de um vetor em C se dá pela sintaxe:

<tipo de dado> <nome do vetor>[<tamanho>];


<tipo de dado> <nome do vetor>[<tamanho>] = { lista de valores };

Seja um vetor V de inteiros com 5 elementos. Este vetor é declarado na


linguagem C pelo comando:

int V[5];

Para fins práticos, os vetores serão tratados como colunas. As colunas ou


elementos ou células são ordenadas horizontalmente, são numeradas da esquerda
para direita, e são indicadas pelo índice que varia de 0 a n–1, Figura 4.29.

Figura 4.29 Representação de um vetor genérico e seus elementos.


Programação Básica com Linguagem C 140

Na linguagem C a contagem começa em zero (0) e assim, o índice do vetor V


varia de 0 até n–1. Pode–se reescrever V, de modo econômico, como V = [v c], 0 ≤ c
< n.

Exemplo 4.60 O programa abaixo cria um vetor de inteiros, com cem elementos,
atribui valores a estes elementos e imprime o valor de cada elemento.
#include <stdio.h>
int main( void ){
int i, x [100];
for( i = 0; i < 100; i++ )
x[i] = i;
for( i = 0; i < 100; i++ )
printf (" %d ", x[i]);
return 0;
}
Por ter muitos elementos, eles não foram lidos do teclado.

4.10.1.1. Algumas Operações com Vetores


Dentre as operações com vetores, destacam–se a soma, subtração, a
multiplicação por número real e o produto escalar.
Dados os vetores A = [a 0 a1 a2 … an-1] e B = [b0 b1 b2 … bn-1], a soma de A e B é
um outro vetor C, dado por C = [a0+b0 a1+b1 a2+b2 … an-1+bn-1].
A subtração de A e B é um outro vetor S, dada por S = [a 0-b0 a1-b1 a2-b2 … an-1-bn-
1]. E o produto de um número real k pelo vetor A é um outro vetor P, dado por P =

[ka0 ka1 ka2 … kan-1].

Exemplo 4.61 Sejam A = [-1 0 3 1] e B = [1 2 0 -2], calcule C = A+B, S = A - B, P =


5A-3B.
C = [-1+1 0+2 3+0 1-2] = [0 2 3 -1]
S = [-1-1 0-2 3-0 1+2] = [-2 -2 3 3]
P = [ 5x(-1)-3x1 5x0-3x2 5x3-3x0 5x1-3x(-2)] = [-8 -6 15 11]

Pode-se ainda ordenar os elementos dos vetores, embaralhá-los e estatísticas


diversas como valores extremos e média.
4.10.1.2. Aplicações com Vetores
A linguagem C exige que o tamanho do vetor seja um valor constante inteiro,
isto é, um valor inteiro que não varia – não pode ser uma variável. É comum a
seguinte declaração na linguagem C para um vetor:

#define n 20
float V[n]; // n é constante e V possui 20 elementos do tipo float

Para fazer referência a um dos valores do vetor em C, basta usar o nome do


Programação Básica com Linguagem C 141

vetor e indicar o índice desejado, lembre–se que o índice varia de 0 a n–1. Na


declaração anterior, V[0] é o primeiro elemento de V, V[1] é o seu segundo
elemento, e assim por diante, até V[19], que é seu último elemento. Não existe o
elemento V[20] pois a contagem começa em zero (0).
Observe que o padrão usado para percorrer o vetor V: V[0], V[1], V[2], …, V[19],
ou seja, V[c], 0 ≤ c < n, é similar ao padrão do comando for. Vetores podem ser
manipulados na linguagem C por meio de comando for, eles foram feitos um para o
outro, da seguinte forma:

#define n 20
int c;
float V[n];

for( c = 0; c < n; c++ ){


// comandos para manipular cada elemento V[c] do vetor V
}

No laço acima, o comando for varia o seu contador de repetição de 0 a n–1. O


contador do laço é usado como índice para os elementos do vetor V. A medida que
c aumenta de um em um, o bloco é executado e percorre–se os elementos de V do
início ao fim.

Exemplo 4.62 Leitura e impressão dos valores de um vetor float.


#include <stdio.h>
#define n 10
int main( void ){
int c;
float V[n];
printf("\n\n Leitura de V" );
for( c = 0; c < n; c++ ){
printf(" De o valor de V[%d]: ", c );
scanf("%f", &V[c] );
}
printf("\n\n Impressao de V" );
for( c = 0; c < n; c++ ){
printf("\n V[%d] = %f", c, V[c] );
}
return 0;
}
O programa é inciado pela função main. Nela é declarada uma variável int
contador, para ser usada para controle do laço for como sua condição de parada,
logo é necessário atribuir um valor inicial para esta variável, no caso este valor é
zero (0).
Programação Básica com Linguagem C 142

Exemplo 4.63 Leitura e impressão dos valores de um vetor int.


#include <stdio.h>
#define n 10
int main( void ){
int c;
int V[n];
printf("\n\n Leitura de V" );
for( c = 0; c < n; c++ ){
printf(" De o valor de V[%d]: ", c );
scanf("%d", &V[c] );
}
printf("\n\n Impressao de V" );
for( c = 0; c < n; c++ ){
printf("\n V[%d] = %d", c, V[c] );
}
return 0;
}
O programa que lê V float é muito similar ao programa que lê V int. Muda apenas
os formatos de entrada e saída de V[i], %f para float e %d para int. Não tem como
errar, mas, mesmo assim, é muito comum errar o uso de tipos de entrada e saída
em C.
Uma maneira de verificar se houve erro na entrada de dados é imprimir os dados
lidos e certificar se as entradas são iguais às saídas.

Sejam os vetores A = [a c] e B = [bc], para 0 ≤ c < n. Sejam C = A + B, S = A – B


e P = k A, para k real, logo, pode–se escrever C = [a c+bc], S = [ac-bc] e P = [kac],
para 0 ≤ c < n.
Estas operações com vetores podem ser escritas em C usando o laço for, como
se segue.

Exemplo 4.64 Leitura de A e B vetores de tamanho n, cálculo e impressão de C = A


+ B, S = A – B e P = k A, k número float. Teste este algoritmo com A =[ 2.5 -3.3 4.0
1.2 ], B = [ 0.5 -1.5 2.2 -2.0] e k = 4.0.
#include <stdio.h>
#define n 4

int main( void ){


int c;
float A[n], B[n], C[n], S[n], P[n], k;

printf("\n\n Leitura de A" );


for( c = 0; c < n; c++ ){
printf(" De o valor de A[%d]: ", c );
Programação Básica com Linguagem C 143

scanf("%f", &A[c] );
}

printf("\n\n Leitura de B" );


for( c = 0; c < n; c++ ){
printf(" De o valor de B[%d]: ", c );
scanf( "%f", &B[c] );
}
printf("\n\n De o valor de k: " );
scanf("%f", &k );

printf("\n\n Calculo de C, S e P" );


for( c = 0; c < n; c++ ){
C[c] = A[c] + B[c];
S[c] = A[c] – B[c];
P[c] = k*A[c];
}

printf("\n\n Impressao de C: " );


for( c = 0; c < n; c++ ){
printf( " %f ", C[c] );
}

printf("\n\n Impressao de S: " );


for( c = 0; c < n; c++ ){
printf( " %f ", S[c] );
}

printf("\n\n Impressao de P: " );


for( c = 0; c < n; c++ ){
printf( " %f ", P[c] );
}

return 0;
}
Programa de uso geral, para qualquer tamanho de vetor n.

Exemplo 4.65 Atribuindo valores iniciais para vetores.


#include <stdio.h>
#define n 4
Programação Básica com Linguagem C 144

int main( void ){


int c;
float V[n] = { 1.0, -2.0, 3.1, 4.2 };
printf("\n\n Impressao formatada de V: " );
for( c = 0; c < n; c++ ){
printf(" %f ", V[c] );
}
return 0;
}
Para atribuir valores para um vetor basta organizá–los separados por vírgula e
entre colchetes.

Exemplo 4.66 Leitura de vetores, cálculo e impressão de C = A + B usando


funções.
#include <stdio.h>

#define n 4
float A[n], B[n], C[n];
void LeiaA( void ){
int c;
printf("\n\n Leitura de A" );
for( c = 0; c < n; c++ ){
printf(" De o valor de A[%d]: ", c );
scanf("%f", &A[c] );
}
}

void LeiaB( void ){


int c;
printf("\n\n Leitura de B" );
for( c = 0; c < n; c++ ){
printf(" De o valor de B[%d]: ", c );
scanf("%f", &B[c] );
}
}

void SomaAB( void ){


int c;
printf("\n\n Calculo de C = A + B" );
Programação Básica com Linguagem C 145

for( c = 0; c < n; c++ ){


C[c] = A[c] + B[c];
}
}

void ImprimeC( void ){


int c;
printf("\n\n Impressao de C: " );
for( c = 0; c < n; c++ ){
printf(" %f ", C[c] );
}
}

int main( void ){


LeiaA();
LeiaB();
SomaAB();
ImprimeC();
return 0;
}
Este código, organizado em funções, permitiu a modularização com a criação de
funções especializadas em leitura, soma e impressão de resultados. Estas funções
são void, sem parâmetros e sem return.
As matrizes foram declaradas fora dos blocos das funções, sendo globais a todas
elas.
A função main apenas chama as demais funções de modo ordenado e se encerra.

4.10.1.3. Obtendo Máximo e Mínimo de Vetor


A Tabela 4.21 estabelece os procedimentos computacionais para as operações
de mínimo e máximo, no caso de vetor.

Tabela 4.21 Operações para obtenção dos valores mínimo e máximo de vetores e
seus algoritmos
Operação Procedimento
cria-se uma variável Xmin. O valor inicial de Xmin deve ser o valor do primeiro
elemento do vetor, Xmin = V[0]. Dentro da estrutura de repetição que percorre o
Mínimo
vetor, coloque o comando if( Xmin > V[i] ) Xmin = V[i];. Ao sai do laço o valor de
Xmin é o valor mínimo dentre os elementos do vetor.
cria-se uma variável Xmax. O valor inicial de Xmax deve ser o valor do primeiro
elemento do vetor, Xmax = V[0]. Dentro da estrutura de repetição que percorre o
Máximo
vetor, coloque o comando if( Xmax < V[i] ) Xmax = V[i];. Ao sai do laço o valor de
Xmax é o valor máximo dentre os elementos do vetor.

Observe que, no caso de vetores, tanto seu valor máximo quanto seu valor
Programação Básica com Linguagem C 146

mínimo podem ser inicialmente iguais ao primeiro elemento do vetor. E, se estes


valores não forem seus valores extremos, serão trocados dentro do laço for.

Exemplo 4.67 Obtenha os valores mínimo e máximo do vetor A de 200 elementos


lidos to teclado.
Os dados de entrada são os valores do vetor A – seja ele do tipo float.
Os dados de saída são os valores mínimo e máximo do vetor A, sejam eles Vmin e
Vmax, ambos float – mesmo tipo de A.
Inicialmente, devem ser lidos os valores do vetor.
Para obter o valor mínimo de A, que é Vmin, ele terá valor inicial igual a A[0].
Para obter o valor máximo de A, que é Vmax, ele terá valor inicial igual a A[0]
também.
Onde colocar os comandos Vmin = A[0] e Vmax = A[0], é muito importante. Eles
devem ser colocados após a leitura dos valores de A, e não antes.
Dentro do laço for serão colocados os comandos conforme a Tabela 4.21.
Ao sair do laço for, serão impressos os valores Vmin e Vmax.
#include <stdio.h>
#define N 200
int main( void ){
int c;
float A[n], Vmin, Vmax;

printf("\n\n Leitura de A" );


for( c = 0; c < N; c++ ){
printf(" De o valor de A[%d]: ", c );
scanf("%f", &A[c] );
}

Vmin = A[0];
Vmax = A[0];

printf("\n\n Atualizando Vmin e Vmax: " );

for( c = 0; c < N; c++ ){


if( Vmin > A[c] ) Vmin = A[c];
if( Vmax < A[c] ) Vmax = A[c];
}

printf( "\n menor valor: %f ", Vmin );


printf( "\n maior valor: %f ", Vmax );

return 0;
Programação Básica com Linguagem C 147

}
No início, o acadêmico fica um pouco confuso com estes procedimentos mas, ao
praticá-los, serão abstraídos e se tornarão boas práticas de programação.

4.10.1.4. Busca em Vetor

4.10.1.5. Ordenação de Vetores


Um método simples para ordenar vetores consiste em percorrer o vetor e
perguntar para cada elemento: à direita do elemento há elemento maior do que
ele? Se houver faze-se a troca utilizando uma variável auxiliar. Neste caso, a ordem
é crescente. Se trocar maior por menor então a ordem é decrescente.

Exemplo 4.68 Ordenação de vetor em ordem decrescente.


#include <stdio.h>
#define n 5
int main( void ){
int c, V[n] = { 1, 4, 5, 3, 6 };
for( c = 0; c < n; c++ ){
int i;
for( i = c; i < n; i++ )
if( V[c] < V[i] ){
int aux = V[c];
V[c] = V[i];
V[i] = aux;
}
}
printf("\n\n V: " );
for( c = 0; c < n; c++ )
printf(" %d ", V[c] );
return 0;
}

Exemplo 4.69 Ordenação de vetor em ordem crescente, usando uma função para
trocar.
#include <stdio.h>
#define n 5
void troca( int *a, int *b ){
int aux = *a;
*a = *b;
*b = aux;
Programação Básica com Linguagem C 148

}
int main( void ){
int c, V[n] = { 4, 5, 1, 3, 6 };
for( c = 0; c < n; c++ ){
int i;
for( i = c; i < n; i++ )
if( V[c] > V[i] ) troca(&V[c],&V[i]);
}
printf("\n\n V: " );
for( c = 0; c < n; c++ )
printf(" %d ", V[c] );
return 0;
}
4.10.1.6. Vetor e Apontador
A Linguagem C convencionou que o nome do vetor estático é também seu
apontador, ele apontar para a sua primeira posição.
Seja int V[5] um vetor estático, como declarado abaixo.

int V[5] = { 4, 5, 1, 3, 6 };

Pela convenção, V é o apontador de V[n], válido depois da declaração de V.


Logo, V é o mesmo que &V[0].
Seja int V[5] um vetor estático, e um apontador p, como declarado abaixo.

int *p, V[5] = { 4, 5, 1, 3, 6 };

Logo, V e p = &V[0] apontam para o mesmo endereço de memória.


4.10.1.7. Vetor e Função
Programas C podem receber vetores como parâmetros.
Seja int V[5] um vetor estático, como declarado abaixo.

int V[5] = { 4, 5, 1, 3, 6 };

A função f é a forma mais geral de passar vetor como parâmetro de função.

void f( int *V );

Passar vetor para como parâmetro de função consiste no endereço da primeira


posição do vetor. O parâmetro da função deve ser um apontador para o mesmo tipo
de dado do vetor.
Diz-se que “passar um vetor para uma função” é mesmo que “passar o
endereço inicial do vetor para a função” ou o mesmo que “passar o nome do vetor
para a função”.

Exemplo 4.70 Leitura, escrita e soma de vetor usando funções e apontadores.


Programação Básica com Linguagem C 149

#include<stdio.h>
void Ler( int *X, int n ){
int c;
printf("\n Lendo V");
for( c = 0; c < n; c++ ){
printf("\n De V[%d]: ", c );
scanf( "%d", &X[c] );
}
}
void Escrever( int *X, int n ){
int c;
printf("\n Escrevendo V: ");
for( c = 0; c < n; c++ )
printf(" %d ", X[c] );
}
}
int Soma( int *X, int n ){
int c, S = 0;
for( c = 0; c < n; c++ )
S += X[c];
return S;
}
int main( void ){
int V[5];
Ler(V,5);
Escrever(V,5);
printf("\n Soma de V = %d", Soma(V,5) );
return 0;
}

Exemplo 4.71 Exemplo de passagem de vetor estático como parâmetro de função.


Cálculo da media e da variância de 10 números reais.
#include <stdio.h>
void dados( int n, float *X ){
int c;
for( c = 0; c < n; c++ )
X[c] = rand() % 10;
printf("\nV: " );
for( c = 0; c < n; c++ )
printf( " %3.1f ", X[c] );
}
Programação Básica com Linguagem C 150

float media( int n, float *X ){


int c;
float S = 0.0;
for( c = 0; c < n; c++ )
S += X[c];
return S/n;
}
float variancia( int n, float *X, float m ){
int c;
float S = 0.0;
for( c = 0; c < n; c++ )
S += (X[c]-m) * (X[c]-m);
return S/n;
}
int main ( void ){
float med, var, V[10];
dados(10,V);
med = media(10,V);
var = variancia(10,V,med);
printf( "\nMedia = %f\nVariancia = %f", med, var );
return 0;
}

Reescreva os exemplos acima usando funções e apontadores.


4.10.1.8. Resumo

Estude o Capítulo 4 – Matrizes e Strings.

4.10.1.9. Exercícios – resolva usando funções e apontadores


1. Ler 8 elementos de um vetor A. Construir um vetor B de mesma dimensão de A tal
que B = 3A. Imprimir B.
2. Ler o vetor A com 5 elementos e B com 7 elementos. Construir um vetor C, sendo
esta a junção de A e B. Desta forma, C deverá ter a capacidade de armazenar 12
elementos.
3. Faça um programa que preencha um vetor com seis elementos numéricos inteiros.
Calcule e mostre:
a) todos os números pares;
b) a quantidade de números pares;
c) todos os números ímpares;
Programação Básica com Linguagem C 151

d) a quantidade de números ímpares.


4. Faça um programa que preencha um vetor com sete números inteiros, calcule e
mostre:
5. Faça um
a) os números múltiplos de 2;
b) os números múltiplos de 3;
c) os números múltiplos de 2 e de 3.
2.
6. Faça um programa que preencha um vetor com quinze elementos inteiros e verifique
a existência de elementos iguais a 30, mostrando as posições em que apareceram.
7. Faça um programa que preencha um vetor com dez números reais, calcule e mostre
a quantidade de números negativos e a soma dos números positivos desse vetor.
8. Faça um programa que preencha um vetor com os códigos de sete alunos e carregue
outro vetor com a média final desses alunos. Calcule e mostre: a) o código do aluno
com maior média (desconsiderar empates); b) para cada aluno não aprovado, isto é,
com média menor que 7, mostrar quanto esse aluno precisa tirar na prova de exame
final para ser aprovado. Considerar que a média para aprovação no exame é 5.
9. Faça um programa que receba dez números inteiros e armazene-os em um vetor.
Calcule e mostre dois vetores resultantes: o primeiro com os números pares e o
segundo, com os números ímpares.
10.Faça um programa que receba o código de cinco produtos e seus respectivos preços.
Calcule e mostre: a) a quantidade de produtos com preço inferior a R$ 50,00; b) o
código dos produtos com preço entre R$ 50,00 e R$ 100,00; c) a média dos preços
dos produtos com preço superior a R$ 100,00.
11.Faça um programa que preencha dois vetores de dez posições cada, determine e
mostre um terceiro contendo os elementos dos dois vetores anteriores ordenados de
maneira decrescente.
12.Faça um programa que preencha um vetor com quinze números, determine e
mostre: a) o maior número e a posição por ele ocupada no vetor; b) o menor
número e a posição por ele ocupada no vetor.
13.Faça um programa que leia dois vetores de dez posições e faça a multiplicação dos
elementos de mesmo índice, colocando o resultado em um terceiro vetor. Mostre o
vetor resultante.
14.Faça um programa que leia um vetor com dez posições para números inteiros e
mostre somente os números positivos.
15.Faça um programa que leia um vetor com dez posições para números inteiros. Crie
um segundo vetor, substituindo os valores nulos por 1. Mostre os dois vetores.
16.Faça um programa que leia um vetor A de dez posições. Em seguida, compacte o
vetor, retirando os valores nulos e negativos. Armazene esse resultado no vetor B.
Mostre o vetor B (o vetor B pode não ser preenchido).
17.Faça um programa que leia dois vetores (A e B) com cinco posições para números
inteiros. O programa deve, então, subtrair o primeiro elemento de A do último de B,
acumulando o valor, subtrair o segundo elemento de A do penúltimo de B,
acumulando o valor e assim por diante. Ao final, mostre o resultado de todas as
subtrações realizadas.
18.Faça um programa que leia um vetor com quinze posições para números inteiros.
Programação Básica com Linguagem C 152

Depois da leitura, divida todos os seus elementos pelo maior valor do vetor. Mostre o
vetor após os cálculos.
19.Faça um programa que receba o código de oito clientes e armazene-os em um vetor.
Em um segundo vetor, armazene a quantidade de livros comprados em 2017 por
cada um dos oito clientes. Sabe-se que, para cada dez livros comprados, o cliente
tem direito a um livro grátis. Faça um programa que mostre o código de todos os
clientes, com a quantidade de livros grátis a que ele tem direito.
20.Uma escola deseja saber se existem alunos cursando, simultaneamente, as
disciplinas Lógica e Linguagem de Programação. Coloque os números das matrículas
dos alunos que cursam Lógica em um vetor, quinze alunos. Coloque os números das
matrículas dos alunos que cursam Linguagem de Programação em outro vetor, dez
alunos. Mostre o número das matrículas que aparecem nos dois vetores.
21.Faça um programa que receba o total das vendas de cada vendedor de uma loja e
armazene-as em um vetor. Receba também o percentual de comissão a que cada
vendedor tem direito e armazene-os em outro vetor. Receba os códigos desses
vendedores e armazene-os em um terceiro vetor. Existem apenas dez vendedores na
loja. Calcule e mostre: a) um relatório com os códigos dos vendedores e os valores a
receber referentes à comissão; b) o total das vendas de todos os vendedores; c) o
maior valor a receber e o código de quem o receberá; d) o menor valor a receber e
o código de quem o receberá.
22.Faça um programa para controlar o estoque de mercadorias de uma empresa.
Inicialmente, o programa deverá preencher dois vetores com dez posições cada,
onde o primeiro corresponde ao código do produto e o segundo, ao total desse
produto em estoque. Logo após, o programa deverá ler um conjunto indeterminado
de dados contendo o código de um cliente e o código do produto que ele deseja
comprar, com a quantidade. Código do cliente igual a zero indica fim do programa. O
programa deverá verificar: a) se o código do produto solicitado existe. Se existir,
tentar atender ao pedido; caso contrário, exibir mensagem Código inexistente; b)
cada pedido feito por um cliente só pode ser atendido integralmente. Caso isso não
seja possível, escrever a mensagem Não temos estoque suficiente dessa mercadoria.
Se puder atendê-lo, escrever a mensagem Pedido atendido. Obrigado e volte
sempre; c) efetuar a atualização do estoque somente se o pedido for atendido
integralmente; d) no final do programa, escrever os códigos dos produtos com seus
respectivos estoques já atualizados.
23.Uma maneira de embaralhar um vetor de tamanho N par é aplicar sucessivas
operações E1 e E2, como apresentado na tabela abaixo para N = 10. A primeira
operação troca as metades do vetor e a segunda gira o vetor uma posição à
esquerda como se ele fosse circular. Faça um programa em C que crie, atribua
valores a um vetor e aplique nele as operações E1 e E2, nessa sequência. Imprima
os resultados formatados a cada etapa como a tabela abaixo.

i 0 1 2 3 4 5 6 7 8 9
v[i] 1 2 3 4 5 6 7 8 9 10
E1 6 7 8 9 10 1 2 3 4 5
E2 7 8 9 10 1 2 3 4 5 6
Programação Básica com Linguagem C 153

24.Faça um programa que verifica se um CPF é válido.


25.Dados dois vetores A e B de tamanho N, faça um programa que calcule a soma dos
produtos de ai pelos demais elementos de A e atribua este resultado a b i, e imprima
estes vetores.
26.Explique a saída do programa:

#include <stdio.h>
#define N 4
int main( void ){
char c[N], *pc = &c;
int i[N], *pi = &i;
long l[N], *pl = &l;
float f[N], *pf = &f;
double d[N], *pd = &d;
int k;
for( k = 0; k < N; k++ ){
printf("\n Interacao %d", k );
printf("\n ----------------------------");
printf("\n endereco pc = %p", pc );
printf("\n endereco pi = %p", pi );
printf("\n endereco pl = %p", pl );
printf("\n endereco pf = %p", pf );
printf("\n endereco pd = %p", pd );
printf("\n\n");
pc++;
pi++;
pl++;
pf++;
pd++;
}
return 0;
}

27.Explique a saída do programa:

#include <stdio.h>
#define N 4
int main( void ){
int k, P[N], Q[N], *p;
p = Q;
for( k = 0; k < N; k++ ){
P[k] = k+1;
*(p+k) = k+1;
}
printf("\n P: " );
Programação Básica com Linguagem C 154

for( k = 0; k < N; k++ )


printf(" %d ", P[k] );
printf("\n Q: " );
for( k = 0; k < N; k++ )
printf(" %d ", Q[k] );
return 0;
}

28.Explique a saída do programa, compare-o com o programa anterior:

#include <stdio.h>
#define N 4
int main( void ){
int k, P[N], Q[N], R[N], *p;
p = Q;
for( k = 0; k < N; k++ ){
P[k] = k+1;
*(p+k) = k+1;
}
p = R;
for( k = 0; k < N; k++ ){
*p = k+1;
p++;
}
printf("\n P: " );
for( k = 0; k < N; k++ )
printf(" %d ", P[k] );
printf("\n Q: " );
for( k = 0; k < N; k++ )
printf(" %d ", Q[k] );
printf("\n R: " );
for( k = 0; k < N; k++ )
printf(" %d ", R[k] );
return 0;
}

29.Explique a saída do programa:

#include <stdio.h>
#define n 5
int main( void ){
int c, v[n] = { 4, 5, 1, 3, 6 };
printf("\n");
for( c = 0; c < n; c++ )
printf(" %d ", v[c] );
Programação Básica com Linguagem C 155

printf("\n");
for( c = 0; c < n; c++ )
printf(" %d ", *(v+c) );

return 0;
}

30.Explique a saída do programa:

#include <stdio.h>
#define n 5
int main( void ){
int c, v[n] = { 4, 5, 1, 3, 6 };
for( c = 0; c < 2*n; c++ )
printf(" %d ", v[c] );
return 0;
}

4.10.2. Strings
O tipo de dado string da Linguagem C tem características similares às do tipo de
dados Vetor, ou seja:

• Alocação estática (deve–se conhecer as dimensões da estrutura no momento da


declaração)
• Estrutura homogênea (armazenam valores do tipo de dado char)
• Alocação sequencial (bytes contíguos na memória)
• Operações relacionadas a texto e carcteres
• Realocação dos elementos

As string não são vetores de caracteres, mas tem comportamentos similares.


Uma string C é uma sequência ordenada de caracteres terminada em NULL
(NULL é 0000 0000). Elas são flexíveis, pode-se diminuir o tamanho de uma string
reposicionando o terminador NULL.

NULL

string - lista indexada de valores do tipo char terminada em NULL

A sequência de caracteres terminada em NULL é o único tipo de cadeia de


Programação Básica com Linguagem C 156

caracteres definido por C, são usadas representar textos na memória do


computador.
Ao declarar uma string é necessário declará-la com um tamanho capaz de
armazenar a maior string a ser utilizada. Por exemplo, para declarar str que pode
conter uma sequência de 10 caracteres se escreve:

char str[11];

Especificando 10 para o tamanho da string e reservando espaço para o NULL no


final da cadeia.

Exemplo 4.72 A string sz[7] foi declarada com valor "abcdefg", pode-se imprimir a
string toda de uma vez ou carácter a carácter. Uma representação gráfica é
mostrada, relacionado estas operações.
char sz[7] = "abcdef";

printf( "%s", sz );
printf( "\n" );
printf( "%c", sz[0] );
printf( "%c", sz[1] );
printf( "%c", sz[2] );
printf( "%c", sz[3] );
printf( "%c", sz[4] );
printf( "%c", sz[5] );

a b c d e f \0

0 1 2 3 4 5 6

a b c d e f \0

Exemplo 4.73 A string sz[7] foi declarada e teve seus caracteres atribuídos
manualmente, neste caso é necessário atribuir o ‘\0’ via código (manualmente).
char sz[7];

sz[0] = ‘a’;
sz[1] = ‘b’;
sz[2] = ‘c’;
sz[3] = ‘d’;
sz[4] = ‘e’;
sz[5] = ‘f’’
Programação Básica com Linguagem C 157

sz[6] = ‘\0’;

printf( "%s", sz );

Exemplo 4.74 A string sz[7] pode declarada com valor inicial similarmente ao
usado em vetores.
char sz[7] = { ‘a’, ’b’, ’c’, ’d’, ’e’, ’f’ };
int c;

printf( "%s", sz );
printf("\n");
for( c = 0; c < strlen(sz); c++ )
printf( "%c", sz[c] );
Na declaração e atribuição, feitas simultaneamente, o compilador atribuir o ‘\0’
automaticamente. Nas demais operações é necessário atribuir o ‘\0’ via código.
Pergunte sempre: tenho ou não tenho que atribuir o ‘\0’ via código?

Exemplo 4.75 A primeira ocorrência de ‘\0’ coloca fim na string, o resultado é


apenas abc.
char sz[7];

sz[0] = ‘a’;
sz[1] = ‘b’;
sz[2] = ‘c’;
sz[3] = ‘\0’;
sz[4] = ‘e’;
sz[5] = ‘f’’
sz[6] = ‘\0’;

printf( "%s", sz );
Se não encontrar ‘\0’ a string não acaba, sz avançará o quanto puder na memória
da máquina, é um erro muito grave.

Operações envolvendo string devem ser feitas com muito cuidado pois o
tamanho das strings são definidas e manipuladas manualmente, o compilador não
faz isso automaticamente.
4.10.2.1. Operações do Tipo de Dado string
A Biblioteca Padrão possui funções para a manipulação de strings, definidas na
em <string.h>, as mais comuns são listadas abaixo:
Programação Básica com Linguagem C 158

Tabela 4.22 Funções C para manipulação de string


Função Ação
gets(s) lê s de stdin
puts(s) Escreve a string s na tela
strcpy(s1,s2) copia s2 em s1
strncpy(s2,s1,n) copia até n caracteres de s1 para s2
strcat(s1,s2) concatena s2 no final de s1
strlen(s) retorna o tamanho de s
strcmp(s1,s2) retorna menor que 0 se s1 < s2; 0 se s1==s2; maior que 0 se s1> s2
strchr(s,c) retorna um ponteiro para a primeira ocorrência de c em s
strstr(s1,s2) retorna um ponteiro para a primeira ocorrência de s2 em s1
strrchr(s,c) retorna um ponteiro para a primeira ocorrência de c em s
memcpy(s1,s2,n) copia n caracteres de s2 em s1
memset(s,c,n) preenche s com n valores de c
s = sprintf(...) uso do printf para escrever em s
fgets(s,n,stdin) Lê uma linha de stdin, com até n-1 caracteres, armazenando em s

Exemplo 4.76 Este código mostra o uso de algumas funções para manipulação de
strings.
#include<stdio.h>
#include<string.h>
int main(void){
char s1[80], s2[80];
gets(s1);
gets(s2);
printf ("comprimentos: %d %d\n", strlen(s1), strlen(s2));
if( !strcmp(s1,s2) ) printf ("As strings são iguais \ n");
strcat(s1,s2);
printf ("%s\n", s1);
strcpy(s1,"Isto é um teste\n");
printf("%s",s1);
if( strchr("Olá",'e') ) printf ("e está em Olá \ n");
if( strstr("oi lá","oi") ) printf ("oi foi encontrado");
return 0;
}

Exemplo 4.77 Este código mostra a relação entre vetores strings, ao receber uma
string de no máximo 20 caracteres e imprimir conteúdo invertido.
#include<stdio.h>
#include<string.h>
int main( void ){
char s[21];
Programação Básica com Linguagem C 159

int n, c;
printf ("\n digite uma string de ate 20 caracteres: " );
gets(s);
n = strlen(s);
printf( "\n s invertida: " );
for( c = n; c >= 0; c-- )
printf (" %c ", s[c]);
printf( "\n s: %s", s );
return 0;
}

Exemplo 4.78 Este programa receba uma string de no máximo 20 caracteres do


usuário, usando scanf, e mostre o conteúdo desta string de forma invertida.
#include<stdio.h>
#include<string.h>
int main( void ){
char s[21];
int n, c;
printf ("\n digite uma string de ate 20 caracteres: " );
scanf("%s", s );
n = strlen(s);
printf( "\n s invertida: " );
for( c = n; c >= 0; c-- )
printf (" %c ", s[c]);
printf( "\n s: %s", s );
return 0;
}

4.10.2.2. A Função main


Programas C podem receber argumentos de linha de comando quando ele inicia.
A função main pode receber dois parâmetros:

int main( int argc, char *argv[] )

Em que, argc indica quantos argumentos foram passados na linha de comando e


argv é um vetor de strings contendo os argumentos passados na linha de comando.
Os argumentos passados para o programa devem ser separados por espaço ou
tabulação. Na primeira posição do vetor argv temos o nome do programa.

Exemplo 4.79 Este código imprime os parâmetros recebidos na linha de comando.


Programação Básica com Linguagem C 160

#include <stdio.h>
int main( int argc, char *argv[] ){
int i;
for( i = 0; i < argc; i++ )
printf( "%s\n", argv[i] );
return 0;
}

Exemplo 4.80 Este código imprime o nome do programa e seus os parâmetros


recebidos na linha de comando, caso existam.
#include <stdio.h>
int main( int argc, char *argv[] ){
printf( "\nPrograma: %s", argv[0] );
if( argc > 1 ){
int i;
printf( "\nParametros: " );
for( i = 1; i < argc; i++ )
printf( " %s ", argv[i] );
}
else printf( "\nChamada sem parametros" );
return 0;
}
Este código é melhor do que o anterior pois testa o valor de argc antes de usá-lo
como índice do vetor argv, evitando erros de lógica (overflow ou underflow).

4.10.2.3. Vetor de strings


Pode-se implementar um vetor de strings simplesmente como uma matriz de
strings, da forma:

char Texto[numero_de_strings][tamanho_das_strings];

Exemplo 4.81 Este código lê e imprime um vetor com 5 strings de tamanho 20.
#include <stdio.h>
#include <string.h>
int main( void ){
char vet[5][21];
int c;
for( c = 0; c < 5; c ++){
printf(" Digite a string %d: ", c );
gets( Texto[c] );
Programação Básica com Linguagem C 161

}
for( c = 0; c < 5; c++ )
printf("\n string: %s", Texto[c] );
return 0;
}

Exemplo 4.82 Este código imprime os parâmetros recebidos na linha de comando.


E se quiséssemos inicializar nossa matriz logo de início?
#include <stdio.h>
int main( void ){
char Texto[5][21] = { "domingo",
"segunda-feira",
"terca-feira",
"quarta-feira",
"quinta-feira"
};
int c;
for( c = 0; c < 5; c++ )
printf("\n string: %s", Texto[c] );
return 0;
}

4.10.2.4. Strings e Ponteiros


A Linguagem C convencionou que o nome da string é também seu apontador,
ele apontar para a sua primeira posição.
Seja str[5] uma string, como declarado abaixo.

char str[5] = “oba!”;

Pela convenção, str é o apontador de str[5], válido depois da declaração de str.


Logo, str é o mesmo que &str[0].

4.10.2.5. String e Função

4.10.2.6. Resumo
Programação Básica com Linguagem C 162

Estude o Capítulo 4 – Matrizes


Estude o Capítulo 13 - Funções de Strings e Caracteres

4.10.2.7. Exercícios
1. Escreva um programa em C que leia uma data, determine e imprima se ela é válida.
Ou seja, verifique se o mês está entre 1 e 12, e se o dia existe naquele mês. Note
que fevereiro tem 29 dias em anos bissextos, e 28 dias em anos não bissextos (um
ano é bissexto se ele for divisível por 4, 100 e 400. Desta forma, 1964 e 2000 são
bissextos, mas 1900 não é bissexto).
2. Faça um programa que lê nome e o sobrenome e imprime o número de letras de
cada um.

4.10.3. Matrizes
Matriz é uma estrutura de dados na forma de tabela, alocados e
sequencialmente e de forma estática. Ela é composta por linhas e colunas e, para
localizar seus elementos, necessita de dois índices, um para a linha e o outro para a
coluna.

matriz – arranjo bidimensional indexado de valores do mesmo tipo

Da mesma forma que Vetores, Matrizes são declaradas com um tamanho fixo,
todos os elementos são do mesmo tipo, todas as células são do mesmo tamanho,
cada célula contém somente um valor e seus elementos ocupam posições contíguas
na memória.
4.10.3.1. Aplicações com Matrizes
A matriz de nome A, com m linhas e n colunas, do tipo float, é declarada na
linguagem C da forma:

float A[m][n];

Se for uma matriz de nome M, com n linhas e m colunas, do tipo int, é declarada
na linguagem C da forma:

int M[m][n];

A linguagem C exige que o tamanho da matriz sejam valores constantes inteiras,


isto é, um valor inteiro que não varia – não pode ser uma variável. É comum a
Programação Básica com Linguagem C 163

seguinte declaração na linguagem C para uma matriz:

#define m 6
#define n 4
float V[m][n]; // n e m são constantes

Para fazer referência a um dos valores da matriz em C, basta usar o seu nome e
indicar os índices desejados da linha e da coluna.
Lembre-se que o índice da linha varia de 0 a m-1 e da coluna varia de 0 a n-1.
Nos laços abaixo, o primeiro for é o laço das linhas da matriz, e o segundo for é
o laço das colunas da matriz.
O for das linhas, faz variar seu contador de repetição de 0 a m-1, este contador
é usado como índice para os elementos das linhas da matriz A. A medida que vai
variando, o bloco é executado assim pode-se percorrer as linhas de A, uma a uma,
do início ao fim.
O for das colunas, faz variar seu contador de repetição de 0 a n-1, este contador
é usado como índice para os elementos das colunas da matriz A. A medida que vai
variando, o bloco é executado assim pode-se percorrer as colunas de A, uma a uma,
do início ao fim.
Os dois laços for em conjunto, ao variar seus contadores de repetição, percorre
as linhas da matriz A de cima para baixo e, as colunas de cada linha é percorrida da
esquerda para a direita, permitindo operar cada elemento A[l][c], um por um.
#define m 20

#define n 20

int l, c;
float A[m][n];

for( l = 0; l < m; l++ ){


for( c = 0; c < n; c++ ){
comandos para manipular o elemento da matriz A
// A[l][c] – elemento da linha l e da coluna c
}
}

Exemplo 4.83 Leitura e impressão dos valores de uma matriz float.


#include <stdio.h>

#define m 4
#define n 3
Programação Básica com Linguagem C 164

int main( void ){


int l, c;
float M[m][n];

printf("\n\n Leitura de M" );


for( l = 0; l < m; l++ ){
for( c = 0; c < n; c++ ){
printf(" De o valor de M[%d][%d]: ", l, c );
scanf("%f", &M[l][c] );
}
}

printf("\n\n Impressao formatada de M" );


for( l = 0; l < m; l++ ){
printf("\n");
for( c = 0; c < n; c++ ){
printf(" %f ", M[l][c] );
}
}

return 0;
}

Sejam as matrizes A, B, C=A+B, S=A-B e P=kA, k real. Estas operações com


matrizes podem escritas em C usando laços for, como se segue.

Exemplo 4.84 Leitura de A e B matrizes de tamanho nxm, cálculo e impressão de C


= A + B, S = A – B e P = k A, k número float.
#include <stdio.h>

#define m 3
#define n 4

int main( void ){


int l, c;
float A[m][n], B[m][n], C[m][n], S[m][n], P[m][n], k;

printf("\n\n Leitura de A" );


for( l = 0; l < m; l++ ){
for( c = 0; c < n; c++ ){
printf(" De o valor de A[%d][%d]: ", l, c );
scanf("%f", &A[l][c] );
Programação Básica com Linguagem C 165

}
}

printf("\n\n Leitura de B" );


for( l = 0; l < m; l++ ){
for( c = 0; c < n; c++ ){
printf(" De o valor de B[%d][%d]: ", l, c );
scanf("%f", &B[l][c] );
}
}

printf("\n\n De o valor de k: " );


scanf("%f", &k );

printf("\n\n Calculo de C, S e P" );


for( l = 0; l < m; l++ ){
for( c = 0; c < n; c++ ){
C[l][c] = A[l][c] + B[l][c];
S[l][c] = A[l][c] – B[l][c];
P[l][c] = k*A[l][c];
}
}

printf("\n\n Impressao formatada de C: " );


for( l = 0; l < m; l++ ){
printf( "\n" );
for( c = 0; c < n; c++ ){
printf(" %f ", C[l][c] );
}
}

printf("\n\n Impressao formatada de S: " );


for( l = 0; l < n; l++ ){
printf( "\n" );
for( c = 0; c < m; c++ ){
printf(" %f ", S[l][c] );
}
}

printf("\n\n Impressao formatada de P: " );


for( l = 0; l < m; l++ ){
printf( "\n" );
Programação Básica com Linguagem C 166

for( c = 0; c < n; c++ ){


printf(" %f ", P[l][c] );
}
}

return 0;
}

Altere o valor de n e m para adequar o tamanho das matrizes.

Exemplo 4.85 Atribuindo valores iniciais para matrizes.


#include <stdio.h>

#define m 3
#define n 4

int main( void ){


int l, c;
float A[m][n] = { { 1.0, -2.0, 3.1, 4.2 },
{ 2.0, 3.1, 2.2, 1.1 },
{ 1.0, 7.0, 3.3, 8.9 }
};

printf("\n\n Impressao formatada de A: " );


for( l = 0; l < m; l++ ){
printf( "\n" );
for( c = 0; c < n; c++ ){
printf(" %f ", A[l][c] );
}
}

return 0;
}
Para atribuir valores para uma matriz basta organizá-los linha a linha, os
elementos da linha separados por vírgula, as linhas entre colchetes separadas por
vírgula, tudo isso entre colchetes.

4.10.3.2. Operações com Linhas, Colunas e Diagonais de Matriz


A Tabela 4.23 estabelece os procedimentos computacionais para as operações
com linhas, colunas e diagonais de matrizes e seus algoritmos.
Programação Básica com Linguagem C 167

Tabela 4.23 Operações com linhas, colunas e diagonais de matrizes e seus


algoritmos
Operação Procedimento
os elementos da linha l de uma matriz A m,n são al,0 al,1 al,2 … al,c … al,n-1, para 0 ≤ c <
n. Para operar sobre todos os elementos da linha l é suficiente um for que varie o
Linhas
índice da coluna e que faça a operação desejada sobre cada elemento da linha l e
coluna c.
os elementos da coluna c de uma matriz A m,n são a0,c a1,c a2,c … al,c … am-1,c, para 0 ≤ l
< m. Para operar sobre todos os elementos de uma coluna c é suficiente um for que
Colunas
varie o índice da linha e que faça a operação desejada sobre cada elemento da linha
l e coluna c.
os elementos da diagonal principal de uma matriz quadrada A m,m são a0,0 a1,1 a2,2 … al,l
Diagonal … am-1,m-1, para 0 ≤ l < m. Para operar sobre todos os elementos da diagonal principal
principal é suficiente um for que varie o índice da linha e que faça a operação desejada sobre
cada elemento da linha l e coluna l.
s elementos da diagonal secundária de uma matriz quadrada Am,m são a0,m-1 a1,m-1 a2,m-3
Diagonal … al,m-1-l … am-1,0, para 0 ≤ l < m. Para operar sobre todos os elementos da diagonal
secundária principal é suficiente um for que varie o índice da linha e que faça a operação
desejada sobre cada elemento da linha l e coluna m-1-l.

Exemplo 4.86 Obtenha a soma das linhas e das colunas da matriz A de dimensão
20 x 30.
Os dados de entrada são os valores do vetor A – sejam ele do tipo float.
Os dados de saída são as somas de cada linha e cada coluna da matriz A.
São necessário declara a matriz A[M][N], e seus contadores l e c, ambos do tipo
int. As constantes M e NM serão declaradas como #define.
Para obter a soma das linhas de A, será usada um laço for para percorrer as linhas
de A, nomeado for linha. Dentro do for linha será declarada a variável S para a
soma das linhas, ela será to tipo for e valor inicial zero (0.0). Ainda dentro for linha,
será usada um laço for para percorrer as colunas de A, nomeado for coluna. Dentro
do for coluna será adicionado o comando para soma S com o valor de cada
elemento A[l][c]. Ao encerrar o for coluna, imprime-se S que corresponde a soma
da linha l.
Os dois for em conjunto permite somar linha a linha de A. Inicialmente, o for linha
tem l = 0. A variável S é declarada e tem valor S = 0.0. O for coluna percorre a
linha l = 0 e soma todos os valores A[0][c]. Encerrado o for coluna o valor de S é
impresso e corresponde a soma da linha 0.
O for linha avança para a próxima linha, l = 1. A variável S é declarada e tem valor
S = 0.0. O for coluna percorre a linha l = 1 e soma todos os valores A[1][c].
Encerrado o for coluna o valor de S é impresso e corresponde a soma da linha 1. E
assim por diante até a linha n-1.
No algoritmo abaixo o for linha está destacado com fundo vermelho e o for coluna
com fundo azul.

O algoritmo para calcular as somas das colunas é similar ao das linhas, exceto que
devem ser trocadas as posições dos for linha e for coluna.
No algoritmo abaixo o for linha está destacado com fundo verde e o for coluna com
Programação Básica com Linguagem C 168

fundo azul.
#include <stdio.h>

#define M 3
#define N 4

int main( void ){


int l, c;
float A[M][N];

printf("\n\n Leitura de A" );


for( l = 0; l < M; l++ ){
for( c = 0; c < N; c++ ){
printf(" De o valor de A[%d][%d]: ", l,c );
scanf("%f", &A[l][c] );
}
}

printf("\n\n Soma das linhas de A" );

for( l = 0; l < M; l++ ){


float S = 0.0;
for( c = 0; c < N; c++ ){
S = S + A[l][c];
}
printf("\n Soma da linha %d: = %f", l, S );
}

printf("\n\n Soma das colunas de A" );

for( c = 0; c < N; c++ ){


float S = 0.0;
for( l = 0; l < M; l++ ){
S = S + A[l][c];
}
printf("\n Soma da coluna %d: = %f", c, S );
}
return 0;
}
Programação Básica com Linguagem C 169

No início, o acadêmico fica um pouco confuso com estes procedimentos mas, ao


praticá-los, serão abstraídos e se tornarão boas práticas de planejamento de
programação.

Exemplo 4.87 Obtenha e imprima a soma das diagonais principal e secundária da


matriz A de dimensão 30 x 30. Faça o mesmo para seus valores máximos e
mínimos.
Os dados de entrada são os valores do vetor A – sejam ele do tipo float.
Os dados de saída são as somas e os valores máximo e mínimo das diagonais da
matriz A.
São necessário declara a matriz A[M][M], e seus contadores l e c, ambos do tipo
int. A constante M será declarada como #define.
Para a diagonal principal serão declaradas:

• a variável Sdp do tipo float para sua soma, com valor inicial zero (0.0)
• a variável DPmin do tipo float para seu mínimo, com valor inicial A[0][0]
• a variável DPmax do tipo float para seu máximo, com valor inicial A[0][0]

Para a diagonal secundária serão declaradas:

• a variável Sds do tipo float para sua soma, com valor inicial zero (0.0)
• a variável DSmin do tipo float para seu mínimo, com valor inicial A[0][N-1]
• a variável DSmax do tipo float para seu máximo, com valor inicial A[0][N-1]

Serão usados apenas um laço for para os cálculos com os comandos descritos na
Tabela 4.23. A final deste do for serão impressos os valores solicitados.
Os comandos para os valores iniciais para DPmin, DPmax, DSmin e DSmax devem
ser colocados após a leitura dos valores de A e não antes.
#include <stdio.h>
#define M 30
int main( void ){
int l;
float A[M][M], Sds, Sdp, DPmin, DPmax, DSmin, DSmax;

Sdp = 0.0;
Sds = 0.0;

printf("\n\n Leitura de A" );

for( l = 0; l < M; l++ ){


for( c = 0; c < M; c++ ){
printf(" De o valor de A[%d][%d]: ", l, l );
scanf("%f", &A[l][l] );
Programação Básica com Linguagem C 170

}
}

DPmin = A[0][0];
DPmax = A[0][0];
DSmin = A[0][M-1];
DSmax = A[0][M-1];

printf("\n\n Calculando … " );

for( l = 0; l < M; l++ ){

Sdp = Sdp + A[l][l];


Sds = Sds + A[l][M-1-l];

if( DPmin > A[l][l] ) DPmin = A[l][l];


if( DPmax < A[l][l] ) DPmax = A[l][l];

if( DSmin > A[l][N-1-l] ) DSmin = A[l][M-1-l];


if( DSmax < A[l][N-1-l] ) DSmax = A[l][M-1-l];

printf( "\n Diagonal Principal " );


printf( "\n Soma : %f ", Sdp );
printf( "\n menor valor: %f ", DPmin );
printf( "\n maior valor: %f ", DPmax );

printf( "\n Diagonal Secundaria " );


printf( "\n Soma : %f ", Sds );
printf( "\n menor valor: %f ", DSmin );
printf( "\n maior valor: %f ", DSmax );

return 0;
}
E uma boa prática de programação criar o dicionário com as varáveis do programa,
seus tipos e valores iniciais. E, o mais importante, a finalidade de cada uma delas,
as operações a realizar com cada uma delas e onde colocar cada comando a elas
referentes. Isso tudo antes de começar a digitar o programa de computador.
No início, o acadêmico fica um pouco confuso com estes procedimentos mas, ao
praticá-los, serão abstraídos e se tornarão boas práticas de planejamento de
Programação Básica com Linguagem C 171

programação.

4.10.3.3. Multiplicação de Matrizes


A multiplicação de duas matrizes é definido somente quando o número de
colunas da primeira matriz é igual ao número de linhas da segunda matriz.
Se A é uma matriz m×n (A m×n) e B é uma matriz n×p (B n×p), C = A·B é uma
matriz m×p (Cm×p), e cada elemento ci,j é dado pelo produto da i-ésima linha de A
com a j-ésima coluna de B, ou seja:
n
c i , j=∑ ai ,r br , j=a i,1 b1 , j +ai ,2 b 2 , j+⋯+ ai , n b n , j , com 1 ≤ i ≤ m e 1 ≤ j ≤ p.
r=1

Exemplo 4.88 Sejam as matrizes A de dimensão 3 x 4, B de dimensão 4 x 3, C =


AB de dimensão 3 x 3. O cálculo de C é como se segue:
#include <stdio.h>
#define M 3
#define N 4
#define P 3
int main( void ){
int i, j, r;
double A[M][N], B[N][P],C[M][P];
printf("\n Leitura de A" );
for( i = 0; i < M; i++ )
for( j = 0; j < N; j++ ){
printf(" De o valor de A[%d][%d]: ", i, j );
scanf("%lf", &A[i][j] );
}
printf("\n Leitura de B" );
for( i = 0; i < N; i++ )
for( j = 0; j < P; j++ ){
printf(" De o valor de B[%d][%d]: ", i, j );
scanf("%lf", &B[i][j] );
}
printf("\n Calculando C = AB … " );
for( i = 0; i < M; i++ )
for( j = 0; j < P; j++ ){
C[i][j] = 0.0;
for( r = 0; r < N; r++ )
C[i][j] = A[i][r]*B[r][j];
}
printf("\n Imprimindo C = AB … " );
for( i = 0; i < M; i++ ){
Programação Básica com Linguagem C 172

printf("\n");
for( j = 0; j < P; j++ )
printf(" %lf ", C[i][j] );
}
return 0;
}

4.10.3.4. Classificação de Matriz


A Tabela 4.24 classifica e descreve os principais tipos de matrizes e suas
propriedades matemáticas.

Tabela 4.24 Tipos de matrizes e suas propriedades matemáticas


Classificação Propriedade
Quadrada m = n, A=[al,c], 0 ≤ l < m e 0 ≤ c < n
se A=[al,c], 0 ≤ l < n e 0 ≤ c < m, então T=[ac,l] é sua matriz transposta, e é
Transposta
representada pot T = AT.
Simétrica se A=[al,c] é matriz quadrada com al,c = ac,l, então A dita simétrica.
A Tabela 4.25 caracteriza as diagonais principal e secundária de uma matriz
quadrada.

Tabela 4.25 Propriedades matemáticas das diagonais principal e secundária de


matrizes quadradas
Diagonal Propriedade
se A=[al,c] é uma matriz quadrada, então os elementos al,c em que l = c são
Principal
elementos de sua diagonal principal
se A=[al,c] é uma matriz quadrada de tamanho n, então os elementos a l,c em que c
Secundária
= n-1-l são elementos de sua diagonal secundária

4.10.3.5. Matriz e Apontador


Matrizes, por ser multidimensional, requer indireção múltipla para seu
endereçamento. A Figura 4.30 representa a indireção múltipla de uma matriz X4x8. O
endereço **X refere-se aos endereços das linhas e o *X aos endereços das colunas
de cada linha. Leia o Erro: Origem da referência não encontrada.

Figura 4.30 Representação gráfica da indireção múltipla de uma matriz X4x8.

4.10.3.6. Matriz e Função


Programação Básica com Linguagem C 173

Matrizes como parâmetros de funções e


Funções retornando matrizes.

Estude o Capítulo 4 – Matrizes e Strings.

4.10.3.7. Resumo

4.10.3.8. Exercícios
1. Faça um programa que preencha uma matriz 3 x 5 com números inteiros, calcule e
mostre a quantidade de elementos entre 15 e 20.
2. Crie um programa que preencha uma matriz 2 x 4 com números inteiros, calcule e
mostre: a) a quantidade de elementos entre 12 e 20 em cada linha; b) a média dos
elementos pares da matriz.
3. Ler 10 elementos de uma matriz A. Construir uma matriz B de mesmo tipo, com a
seguinte lei de formação: todo elemento da matriz B deverá ser o quadrado do
elemento de A correspondente.
4. Elabore um programa que preencha uma matriz 6 x 3, calcule e mostre: a) o maior
elemento da matriz e sua respectiva posição, ou seja, linha e coluna; b) o menor
elemento da matriz e sua respectiva posição, ou seja, linha e coluna.
5. Faça um programa que receba: a) as notas de 15 alunos em cinco provas diferentes
e armazene-as em uma matriz 15 x 5; b) os nomes dos 15 alunos e armazene-os em
um vetor de 15 posições. O programa deverá calcular e mostrar: a) para cada aluno,
o nome, a média aritmética das cinco provas e a situação (aprovado, reprovado ou
exame); b) a média da classe.
6. Elabore um programa que preencha uma matriz 12 x 4 com os valores das vendas
de uma loja, em que cada linha representa um mês do ano e cada coluna representa
uma semana do mês. O programa deverá calcular e mostrar: a) o total vendido em
cada mês do ano, mostrando o nome do mês por extenso; b) o total vendido em
cada semana durante todo o ano; c) o total vendido pela loja no ano.
7. Faça um programa que preencha uma matriz 20 x 10 com números inteiros, e some
cada uma das colunas, armazenando o resultado da soma em um vetor. A seguir, o
programa deverá multiplicar cada elemento da matriz pela soma da coluna e mostrar
a matriz resultante.
8. Elabore um programa que preencha uma matriz M de ordem 4 x 6 e uma segunda
matriz N de ordem 6 x 4, calcule e imprima a soma das linhas de M com as colunas
de N.
9. Crie um programa que preencha duas matrizes 3 x 8 com números inteiros, calcule e
mostre: a) a soma das duas matrizes, resultando em uma terceira matriz também de
ordem 3 x 8; b) a diferença das duas matrizes, resultando em uma quarta matriz
também de ordem 3 x 8.
10.Faça um programa que preencha uma matriz 3 x 3 com números reais e outro valor
Programação Básica com Linguagem C 174

numérico digitado pelo usuário. O programa deverá calcular e mostrar a matriz


resultante da multiplicação do número digitado por cada elemento da matriz.
11.Crie um programa que preencha uma matriz 5 x 5 com números inteiros, calcule e
mostre a soma: a) dos elementos da linha 4; b) dos elementos da coluna 2; c) dos
elementos da diagonal principal; c) dos elementos da diagonal secundária; d) de
todos os elementos da matriz.
12.Elabore um programa que: receba a idade de oito alunos e armazene-as em um
vetor; armazene o código de cinco disciplinas em outro vetor; armazene em uma
matriz a quantidade de provas que cada aluno fez em cada disciplina. O programa
deverá calcular e mostrar: a) a quantidade de alunos com idade entre 18 e 25 anos
que fizeram mais de duas provas em determinada disciplina cujo código é digitado
pelo usuário. O usuário poderá digitar um código não cadastrado; nesse caso, o
programa deverá mostrar uma mensagem de erro; b) uma listagem contendo o
código dos alunos que fizeram menos que três provas em determinada disciplina,
seguido do código da disciplina; c) a média de idade dos alunos que não fizeram
nenhuma prova em alguma disciplina. Cuidado para não contar duas vezes o mesmo
aluno.
13.Elabore um programa que: preencha uma matriz 6 x 4; recalcule a matriz digitada,
onde cada linha deverá ser multiplicada pelo maior elemento da linha em questão;
mostre a matriz resultante.
14.Faça um programa que preencha uma matriz 2 x 3, calcule e mostre a quantidade de
elementos da matriz que não pertencem ao intervalo [5,15].
15.Crie um programa que preencha uma matriz 12 x 13 e divida todos os elementos de
cada linha pelo maior elemento em módulo daquela linha. O programa deverá
escrever a matriz lida e a modificada.
16.Elabore um programa que preencha uma matriz 5 x 5 e crie dois vetores de cinco
posições cada um, que contenham, respectivamente, as somas das linhas e das
colunas da matriz. O programa deverá escrever a matriz e os vetores criados.
17.Faça um programa que preencha e mostre a média dos elementos da diagonal
principal de uma matriz 10 x 10.
18.Crie um programa que preencha uma matriz 5 x 5 de números reais, calcule e
mostre a soma dos elementos da diagonal secundária.
19.Faça um programa que preencha uma matriz 8 x 6 de inteiros, calcule e mostre a
média dos elementos das linhas pares da matriz.
20.Elabore um programa que preencha uma matriz 5 x 5 com números reais e encontre
o maior valor da matriz. A seguir, o programa deverá multiplicar cada elemento da
diagonal principal pelo maior valor encontrado e mostrar a matriz resultante após as
multiplicações.
21.Faça um programa que preencha uma matriz 5 x 5 de números reais. A seguir, o
programa deverá multiplicar cada linha pelo elemento da diagonal principal daquela
linha e mostrar a matriz após as multiplicações.
22.Crie um programa que preencha uma matriz 6 x 10, some as colunas
individualmente e acumule as somas na linha 7 da matriz. O programa deverá
mostrar o resultado de cada coluna.
23.Uma empresa trabalha com três produtos e quatro armazéns localizados de modo
estratégico. Faça um programa de modo a permitir responder às questões: a) a
Programação Básica com Linguagem C 175

quantidade de itens armazenados em cada armazém; b) qual armazém possui menor


estoque; c) qual o custo total de cada produto; d) qual o custo total de cada
armazém.
24.Dada uma matriz Anxm, faça um algoritmo que calcule o desvio padrão σ dos
N

elementos aij em que i = 2 j. O desvio padrão (s) é s=


√ ∑ (xi−m)2
i=1
N−1
25.Tem-se uma matriz de dados contendo altura e sexo, faça um programa em C que
, m=
1
N

∑x .
N i=1 i

calcule e escreva a maior e a menor altura do grupo, a altura média das mulheres e
o número de homens.
26.Escreva uma função em C para imprimir na saída padrão a tabuada da soma de 1 a 5
formatada:
a + b = s a + b = s a + b = s a + b = s a + b = s
1 + 1 = 2 2 + 1 = 3 3 + 1 = 4 4 + 1 = 5 5 + 1 = 6
1 + 2 = 3 2 + 2 = 4 3 + 2 = 5 4 + 2 = 6 5 + 2 = 7
1 + 3 = 4 2 + 3 = 5 3 + 3 = 6 4 + 3 = 7 5 + 3 = 8
1 + 4 = 5 2 + 4 = 6 3 + 4 = 7 4 + 4 = 8 5 + 4 = 9
1 + 5 = 6 2 + 5 = 7 3 + 5 = 8 4 + 5 = 9 5 + 5 = 10
1 + 6 = 7 2 + 6 = 8 3 + 6 = 9 4 + 6 = 10 5 + 6 = 11
1 + 7 = 8 2 + 7 = 9 3 + 7 = 10 4 + 7 = 11 5 + 7 = 12
1 + 8 = 9 2 + 8 = 10 3 + 8 = 11 4 + 8 = 12 5 + 8 = 13
1 + 9 = 10 2 + 9 = 11 3 + 9 = 12 4 + 9 = 13 5 + 9 = 14
1 + 10 = 11 2 + 10 = 12 3 + 10 = 13 4 + 10 = 14 5 + 10 = 15

27.Dados duas matrizes A e B de tamanho M x N, faça um programa que calcule a soma


dos produtos de aij pelos demais elementos da A e atribua este resultado a b ij, e
imprima A e B formatadas.

Nos problemas abaixo, considere a terminologia em relação à figura abaixo:


diagonal está em vermelho, tem a principal e a secundária; vertical e horizontal
estão em azul; em verde é o centro da célula. Alvo k é a matriz quadrada de lado
2k+1.

Exercício 4.30 Considere matrizes Am,n e Bm,n e faça uma função para:
a) gerar valores aleatórios para A
b) calcule bi,j como sendo o máximo da horizontal de a i,j, exceto ai,j
c) calcule bi,j como sendo o mínimo da diagonal principal de a i,j
d) calcule bi,j como sendo a média da diagonal secundária de a i,j
e) calcule bi,j como sendo a média dos elementos do entorno de a i,j, exceto ai,j
f) proponha testes para validar os algoritmos acima
g) imprima a matriz B para cada item acima
Programação Básica com Linguagem C 176

Exercício 4.31 Considere matrizes Am,n e Bm,n e alvo de k elementos, faça uma
função para:
a) gerar valores aleatórios para A
b) calcule bi,j como sendo o máximo da horizontal de a i,j, exceto ai,j
c) calcule bi,j como sendo o mínimo da diagonal principal de a i,j
d) calcule bi,j como sendo a média da diagonal secundária de a i,j
e) calcule bi,j como sendo a média dos elementos do entorno de a i,j, exceto ai,j
f) proponha testes para validar os algoritmos acima
g) imprima a matriz B para cada item acima

Exercício 4.32 Considere matrizes Am,n e Bm,n e alvo de k elementos, faça uma
função para:
a) gerar valores aleatórios para A
b) calcule bi,j como sendo o máximo da horizontal de a i-1,j
c) calcule bi,j como sendo o mínimo da diagonal principal de a i,j+1
d) calcule bi,j como sendo a média da diagonal secundária de a i-1,j-1
e) calcule bi,j como sendo a média dos elementos do entorno de a i+k,j+k
f) proponha testes para validar os algoritmos acima
g) imprima a matriz B para cada item acima

Exercício 4.33 Estenda os conceitos acima para Am,n,p e Bm,n,p e refaça os exercícios
acima.

Exercício 4.34 Aplique os resultados anteriores para criar um campo minado por
meio de uma matriz em que uma posição com valor 0 indica uma mina e, para
cada posição livre, o número de posições adjacentes que contêm bombas.

Exercício 4.35 Considerando matrizes Am,n,p e faça uma função para:

a) gerar valores aleatórios para A


b) calcules as matrizes com as faces externas de A
c) os vetores com as diagonais das faces externas de A
d) os vetores com as diagonais entre os vértices de A
e) a diagonal de A que possui a maior soma dos seus elementos
f) proponha testes para validar os algoritmos acima
Programação Básica com Linguagem C 177

g) imprima os seus resultados


h) refaça os exercícios acima Am,n,p,q.

Exercício 4.36 Crie um vetor V[MxN] e leia-o e escreva-o como se fosse uma matriz
V[M][N].

Exercício 4.37 Diz a lenda do Xadrez que Lahur Sessa pediu a seguinte
recompensa por sua invenção: um grão de trigo para a primeira casa do tabuleiro,
dois para a segunda, quatro para a terceira, oito para a quarta e assim
sucessivamente até a última casa de um total de 64 casas. Se a massa de um grão
de trigo é igual 3,855ˣ10-5 kg e sua densidade é de 7,55 kg/m 3. Faça um programa
em C para calcular a massa e o volume de trigo devido ao brâmane utilizando os
tipos: a) float, b) double e c) long double. Interprete seus resultados.

4.10.4. Estruturas

struct – tipo de dado estruturado, heterogêneo, composto por


variáveis de diferentes tipos
campo – denominação para os dados agrupados em uma struct

As structs, também conhecidas como registros, definem tipos de dados que


agrupam variáveis sob um mesmo tipo de dado. Por exemplo, para armazenar o
nome, a altura, o peso e a idade de uma pessoa, pode-se criar uma struct chamada
Pessoa e agrupar os dados em um único tipo de dado:

Exemplo 4.89 Exemplo de um tipo struct de nome Pessoa com quatro campos,
nome, idade, peso e altura e de uma variável Jose do tipo struct Pessoa.
struct Pessoa{ // define o tipo struct
char Nome[35]; // define o campo Nome
float Peso ; // define o campo Peso
int Idade ; // define o campo Idade
float Altura ; // define o campo Altura
};
struct Pessoa Jose; // declara variável Jose do tipo struct Pessoa
Programação Básica com Linguagem C 178

A Linguagem C permite a criação de dados compostos por meio de struct. Uma


struct pode conter diversas variáveis e permite diferentes tipos, uma struct é um
tipo de dado versátil e heterogêneo. As variáveis de uma struct são denominadas
membros desta struct.
Sintaxe para a definição do tipo struct:

struct NomeDaStruct{
tipo1 var12, ..., var1n;
tipo2 var22, ..., var2n;

tipok vark2, ..., varkn;
};

Declaração de variáveis de tipo struct:

struct NomeDaStruct var1, ..., varN;

Exemplo de declaração de uma struct

struct Aluno{
char nome[50], disciplina[30];
float media, nota[3];
};

A struct Aluno permite armazenar os dados de estudantes em uma única


variável. Neste caso, nome, disciplina, três diferentes notas e a media, tudo isto em
uma só variável. Pode-se ainda criar uma turma com 50 estudantes, como a seguir:

struct Aluno Turma[50];

No exemplo acima, Turma é um vetor de 50 struct Aluno. A Turma[i], por sua


vez, possui os membros nome, disciplina, nota[0], nota[1], nota[2] e média, para i
∈ [0,50).
A referência aos elementos da estrutura é feita pelo nome da variável, ponto e
nome do elemento. Por exemplo: Turma[4].nome.

Exemplo 4.90 Este código declara uma estrutura de nome pessoa com quatro
campos, nome, idade, peso e altura:
struct pessoa{
char nome[35];
int idade;
float peso, altura;
} x;
A variável x é do tipo pessoa, uma estrutura criada no programa, x também é
denominada registro.
Programação Básica com Linguagem C 179

Para se referir a um campo de um registro, basta escrever o nome do registro e o


nome do campo separados por um ponto: x.nome, x.idade, x.peso, x.altura.

Exemplo 4.91 Este código declara uma estrutura de nome pessoa com quatro
campos, nome, idade, peso e altura. E, simultaneamente, declara três variáveis de
nomes Pedro, Joao e Visitante.
struct pessoa{
char nome[35];
int idade;
float peso, altura;
} Pedro, Joao, Visitante;

strcpy( Pedro.nome, "Pedro da Silva" );


Pedro.idade = 28;
Pedro.peso = 74.8;
Joao.idade = Pedro.idade;
Visitante.idade = Joao.idade = Pedro.idade;

Exemplo 4.92 Leitura e impressão de registros – calculo do IMC – índice de massa


corporal.
#include <stdio.h>
#define n 3

struct pessoa{
char nome[12];
int idade;
float peso, altura, IMC;
};

int main( void ){


int c;
struct pessoa P[n];
printf("\n\n Leitura das pessoas P" );
for( c = 0; c < n; c++ ){
printf(" De o valor do nome de P[%d]: ", c );
scanf("%s", P[c].nome );
printf(" De o valor da idade de P[%d]: ", c );
scanf("%d", &P[c].idade );
printf(" De o valor do peso de P[%d]: ", c );
scanf("%f", &P[c].peso );
Programação Básica com Linguagem C 180

printf(" De o valor da altura de P[%d]: ", c );


scanf("%f", &P[c].altura );
P[c].IMC = 0.0;
}
printf("\n\n Calculo do IMC" );
for( c = 0; c < n; c++ )
P[c].IMC = P[c].peso / ( P[c].altura*P[c].altura );
printf("\n Nome IMC " );
printf("\n ----------------" );
for( c = 0; c < n; c++ )
printf("\n %-12s %3.1f", P[c].nome, P[c].IMC );
return 0;
}
Vale destacar que, neste código, struct pessoa não é uma variável e sim um tipo
declarado globalmente.

Pode-se criar apontadores para estrutura, como abaixo:

struct nome{
tipo1 var1;
tipo2 var2;
tipo3 var3;
} var, *p;

A variável var é do tipo struct nome. Entretanto p é um apontador para o tipo


struct nome. O acesso à variável var1, por exemplo, pode ser feito das formas:

var.var1; // a partir de variável


p->var1; // a partir de apontador

Exemplo 4.93 Este código cria o tipo struct com escopo global. Cria a variável p de
escopo local. Chama a função prn e o ponteiro para o tipo struct, que recebe o
endereço de p vindo da função main. Em seguida, imprime os valores de nome,
idade e altura.
struct Pessoa{
char nome[35];
int idade;
double altura;
};
void prn( struct Pessoa *pessoa ){
printf( "\n\n Dados de Pessoa");
printf( "\n----------------------------");
printf( "\n nome: %s ", pessoa->nome );
Programação Básica com Linguagem C 181

printf( "\n idade: %d anos ", pessoa->idade );


printf( "\n altura: %3.2lf m", pessoa->altura );
printf( "\n\n");
}
int main( void ){
struct Pessoa p = { "Outra pessoa", 20, 1.23 };
prn(&p);
return 0;
}

Exemplo 4.94 Programa de struct com vetor


#include <stdio.h>
#define TAM 3

struct Aluno{
char nome[12];
char disciplina[12];
float nota[3];
float media;
};

void Ler( int n, struct Aluno *T ){


int c;
printf("\n Aluno %d:", n+1 );
printf("\n Nome:" ); scanf("%s", T->nome );
printf("\n Disciplina:" ); scanf("%s", T->disciplina );
printf("\n Primeira nota:" ); scanf("%f",&T->nota[0] );
printf("\n Segunda nota:" ); scanf("%f",&T->nota[1] );
printf("\n Terceira nota:" ); scanf("%f",&T->nota[2] );
T->media = 0.0;
for( c = 0; c < 3; c++ )
T->media += T->nota[c];
T->media /= 3.0;
// T->media = ( T->nota[0]+T->nota[1]+T->nota[2] )/3.0;
}

int main(void){
int c;
struct Aluno Turma[TAM];
for( c = 0; c < TAM; c++ )
Programação Básica com Linguagem C 182

Ler(c,&Turma[c]);
printf( "\n================================================");
printf( "\n No Nome Disciplina Nota 1 Nota 2 Nota 3 Media ");
printf( "\n------------------------------------------------");
for( c = 0; c < TAM; c++ ){
printf("\n");
printf(" %2d", c+1 );
printf(" %-12s", Turma[c].nome );
printf(" %-12s", Turma[c].disciplina );
printf(" %6.1f", Turma[c].nota[0] );
printf(" %6.1f", Turma[c].nota[1] );
printf(" %6.1f", Turma[c].nota[2] );
printf(" %6.1f", Turma[c].media );
}
printf( "\n================================================");
return 0;
}

Exemplo 4.95 Este código obtém a diferença em segundo de duas datas, ele faz
uso do tipo struct tm da Biblioteca Padrão e suas funções para manipulação de.
#include <stdio.h> // printf
#include <time.h> // time_t, struct tm, difftime, time, mktime
int main ( void ){
time_t timer;
struct tm y = {0};
double seconds;

y.tm_hour = 0;
y.tm_min = 0;
y.tm_sec = 0;
y.tm_year = 2000;
y.tm_mon = 0;
y.tm_mday = 1;

time(&timer); // get current time

seconds = difftime(timer,mktime(&y));

printf( "%.f segundos 01/01/2000", seconds );


return 0;
}
fonte: http://www.cplusplus.com/reference/ctime/time/
Programação Básica com Linguagem C 183

4.10.5. União
Uma declaração union determina uma única localização de memória onde
podem estar armazenadas várias variáveis diferentes. A declaração de uma união é
semelhante à declaração de uma estrutura:

union nome{
tipo1 var1;
tipo2 var2;
tipo3 var3;
...
} var, *p;

union Angulo{
int grau;
float radiano;
};

Exemplo 4.96 Código ilustra o uso da estrutura de dados struct union.


#include <stdio.h>
#include <math.h>
union Angulo{
int grau;
float radiano;
};
int main( void ){
union Angulo angulo;

angulo.grau = 180;
printf("\nAngulo: %d graus\n" , angulo.grau );
printf("\nAngulo: %f radianos\n", angulo.radiano );

angulo.radiano = acos(-1);
printf("\nAngulo: %d graus\n" , angulo.grau );
printf("\nAngulo: %f radianos\n", angulo.radiano );
return 0;
}

4.10.6. Campo de bit


Um tipo de estrutura especial denominado campos de bit é um método de
Programação Básica com Linguagem C 184

acessar um único bit em um byte. Interfaces de dispositivos transmitem


informações codificadas em bits dentro de um byte; algumas rotinas de codificação
precisam acessar bits dentro de bytes.

struct nome{
tipo1: comprimento;
tipo2: comprimento;
tipo3: comprimento;

tipon: comprimento;
};

O Campo de bit é declarado como int, unsigned ou signed; campos de bit de


comprimento 1 são unsigned.

Exemplo 4.97 Este código ilustra o uso da estrutura de dados campo de bit.

4.10.7. Enumeração
Enumerações são conjunto de constantes inteiras com nome e especificação de
todos os valores legais.

enum nome {lista} var;

Exemplo 4.98 Este código ilustra o uso da estrutura de dados enumeração.


#include <stdio.h>
enum naipe { ouro, copa, paus, espada };
int main( void ){
enum naipe n1,n2;
n1 = ouro;
n2 = paus;
if( n1 == n2 ) printf ("Cartas de mesmo naipe.");
else printf ("Cartas de naipes diferentes.");
return 0;
}

4.10.8. Typedef
Typedef é uma forma de definir explicitamente novos nomes de tipos de dados.
Sintaxe:
Programação Básica com Linguagem C 185

typedef tipo nome;

Exemplo 4.99 Este código cria um alias (apelido) para os tipos int e double.
#include <stdio.h>

typedef int inteiro;


typedef double real;

int main( void ){


inteiro i;
real x;
return 0;
}

4.10.9. Resumo

Estude o Capítulo 7 – Estruturas, Uniões, Enumerações e Tipos


Definidos pelo Usuário.

4.10.10. Exercícios

1. Faça um programa que criar sequencialmente um baralho com 52 cartas (A, 2, 3 …,


10, Q, J, K) e seus naipes (ouro, copa, paus, espada). Embaralhe as cartas criadas
utilizando a seguintes técnicas: a) embaralhamento "Overhand", b) embaralhamento
Hindu e c) embaralhamento em cascata (veja mais detalhes no site
https://pt.wikihow.com/Embaralhar-Cartas-de-V%C3%A1rias-Formas ou
https://masterzofcards.com/7-tecnicas-mais-dificeis-com-baralho). Se preferir,
invente suas técnicas de embaralhar as cartas, pelo menos três técnicas devem ser
usadas. Exiba o resultado a cada mudança ocorrida no baralho como um todo.

4.11. Arquivos
Para a Linguagem C, um arquivo é um conceito lógico que é aplicado aos
arquivos gravados em memória de massa, como os Discos Rígidos.
Uma representação gráfica do conceito de arquivo é uma sequência de bytes
Programação Básica com Linguagem C 186

finalizada pelo EOF, que indica o seu fim.

EOF
Para o computador todos os arquivos são binários, eles armazenam apenas bits
{0,1}. Aqueles que podem ser manipulados por Editores de Texto são denominados
arquivos-texto. Caso contrário, são denominados arquivos binários.

Figura 4.31 Ilustração de arquivos-texto e binário, com seu EOF.

A Linguagem C utiliza uma estrutura chamada FILE para manipular arquivos por
meio de apontadores.
Sintaxe para declarar apontador FILE:

FILE *p;

A partir desta declaração, pode apontar p para um arquivo. A variável ponteiro p


é denominada descritor de arquivo.

arquivo – sequência ordenada de bytes finalizada por EOF

Da mesma forma que uma variável pode ser associada a uma região da
memória RAM, um descritor de arquivo pode ser associado a uma região da
memória de massa.
As operações sobre arquivos são abertura, leitura, escrita e fechamento.
Depois que um arquivo é aberto, é possível trocar informações entre ele e seu
programa por meio do seu descritor, que pode apontar para qualquer posição do
arquivo, incluindo o seu fim, a posição em que se encontra o EOF.

4.11.1. Abertura de Arquivo


A abertura de um arquivo é feito pela função fopen, que possui o seguinte
protótipo:

FILE *fopen( char *fn, char *modo );

Esta função requer dois parâmetros, ambos string. O primeiro parâmetro é o


nome do arquivo e o segundo é o modo de abertura. Ela retorna o descritor do
arquivo aberto e NULL em caso de erro.
O modo de abertura é uma combinação das opções { abre/cria/anexa,
Programação Básica com Linguagem C 187

texto/binário }, como apresentado na Tabela 4.26.

Tabela 4.26 Modos de abertura de arquivo da função fopen


Modo Descrição
r abre um arquivo-texto para leitura
w cria um arquivo-texto para escrita
a anexa em arquivo-texto
rb abre um arquivo binário para leitura
wb cria um arquivo binário para escrita
ab anexa em arquivo binário
r+ abre um arquivo-texto para leitura/escrita
w+ cria um arquivo-texto para leitura/escrita
a+ anexa ou cria um arquivo-texto para leitura/escrita
r+b abre um arquivo binário para leitura/escrita
w+b cria um arquivo binário para leitura/escrita
a+b anexa ou cria um arquivo binário para leitura/escrita
No Exemplo 4.101 estão os comandos para a abrir o arquivo-texto de nome
c:/Arquivos/file.txt utilizando fopen e seus modos de abertura.

Exemplo 4.100 Exemplo de uso do fopen para abrir o arquivo-texto


c:/Arquivos/file.txt.
char *fn = "c://Arquivos//texto.txt";

FILE *a = fopen(fn, "r" ); //abre um arquivo-texto para leitura


FILE *b = fopen(fn, "w" ); //cria um arquivo-texto para escrita
FILE *c = fopen(fn, "a" ); //anexa em arquivo-texto
FILE *d = fopen(fn, "r+" ); //abre um arquivo-texto para
leitura/escrita
FILE *e = fopen(fn, "w+" ); //cria um arquivo-texto para
leitura/escrita
FILE *f = fopen(fn, "a+" ); //anexa ou cria um arquivo-texto para
leitura/escrita
FILE *g = fopen(fn, "a+b"); //anexa ou cria um arquivo binário para
leitura/escrita

O Exemplo 4.89 estão os comandos para a abrir o arquivo binário de nome


c:/Arquivos/file.bin utilizando fopen e seus modos de abertura.

Exemplo 4.101 Exemplo de uso do fopen para abrir o arquivo binário


c:/Arquivos/file.bin.
char *fn = "c://Arquivos//file.bin";

FILE *a = fopen(fn, "rb" ); //abre um arquivo binário para leitura

FILE *b = fopen(fn, "wb" ); //cria um arquivo binário para escrita

FILE *c = fopen(fn, "ab" ); //anexa em arquivo binário


Programação Básica com Linguagem C 188

FILE *d = fopen(fn, "r+b"); //abre um arquivo binário para leitura/escrita

FILE *e = fopen(fn, "w+b"); //cria um arquivo binário para leitura/escrita

FILE *f = fopen(fn, "a+b"); //anexa ou cria um arquivo binário para leitura/escrita

O uso do fopen implica que:

a) Abrir arquivos para leitura ou anexar requer que ele exista antes de ser aberto
b) Ao abrir um arquivo para escrita, se ele existir então será recriado senão ele será
criado
c) Abre um arquivo para leitura/escrita ou anexar, se ele a escrita será feita ao seu final
(preservando o conteúdo previamente existente) senão será criado

4.11.2. Fechamento de Arquivo


O fechamento de um arquivo é feito pela função fclose, que possui o seguinte
protótipo:

int fclose( FILE *f );

Esta função requer o descritor de um arquivo previamente aberto. Ela retorna


um valor int cujo valor é zero em caso de sucesso e EOF em caso de erro.
A função fclose fecha o arquivo, não importa como foi aberto.

4.11.3. Entrada/Saída em Arquivo


Ler/escrever em arquivos depende do seu modo de abertura.
A leitura/escrita em arquivo-texto é feita pela função fprintf/fscanf:

int fprintf( FILE *f, const char* formato, …);


int fscanf ( FILE *f, const char* formato, …);

Estas funções escreve/lê variáveis formatadas do arquivo-texto apontado por f.


Elas retornam um valor int de valor igual ao número de bytes lidos/escritos em caso
de sucesso e um valor negativo em caso de erro.

A leitura/escrita em arquivo binário é feita pela função fwrite/fread:

size_t fwrite(void *p, size_t tamanho, size_t n, FILE *f );


size_t fread (void *p, size_t tamanho, size_t n, FILE *f );

Estas funções escreve/lê buffer do/no arquivo binário apontado por p; buffer é a
região de memória a ser escrita/lida os dados; tamanho é o número de bytes da
unidade a ser escrita/lida e n é o número de unidades a serem escritas/lidas.
Elas retornam um valor size_t cujo valor é n em caso de sucesso e um valor
menor do que n em caso de erro.
A leitura/escrita de strings e caracteres em arquivo-texto estão descritas na
Tabela 4.27.
Em stdio.h estão as funções para manipular arquivos. Seguem as mais comuns:
Programação Básica com Linguagem C 189

Tabela 4.27 Funções C para manipular arquivos


FILE *fopen( char *fn, char *modo )
abre arquivo texto ou binário
int fclose (FILE *fn)
fecha arquivo previamente aberto
int putc( int c, FILE *fn )
escreve o caractere c (convertido para unsigned char) no arquivo fn
int getc( FILE *fn )
le um caractere do arquivo fn
int feof ( FILE * fn )
retorna true encontrar EOF no arquivo fn
int fputs(const char *str, FILE *p)
escreve str no arquivo-texto apontado por p
char *fgets (char *str, int n, FILE *p)
lê a string str de tamanho n do arquivo-texto apontado por p, retorna str
int fprintf (FILE *p, const char* formato, …)
escreve variáveis formatadas no arquivo-texto apontado por p
int fscanf (FILE *p, const char* formato, …)
lê variáveis formatadas do arquivo-texto apontado por p
size_t fwrite(void* dados, size_t tamanho, size_t n, FILE *p)
escreve dados no arquivo binário apontado por p
size_t fread(void* dados, size_t tamanho, size_t n, FILE *p)
lê dados do arquivo binário apontado por p
int ferror ( FILE *fn )
retorna true se ocorreu algum erro em operações no arquivo fn

Escrevendo/lendo dados em arquivo-texto.

Exemplo 4.102 Este programa escreve/lê dados em/de um arquivo-texto.


#include <stdio.h>
#include <stdlib.h>
void escrever( char *fn ){
char c = 65;
int i = 66;
long l = 67;
float f = 68;
double d = 69;
FILE *fs = fopen( fn, "w" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "Escrevendo valores" );
fprintf(fs, "%s %c %d %ld %f %lf", fn, c, i, l, f, d );
fclose(fs);
}
void ler( char *fn ){
char c;
int i;
long l;
float f;
double d;
Programação Básica com Linguagem C 190

FILE *fe = fopen( fn, "r" );


if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "Lendo valores" );
fscanf(fe, "%s %c %d %ld %f %lf", fn, &c, &i, &l, &f, &d );

printf( "\n fn= %s" , fn);


printf( "\n c = %c" , c );
printf( "\n i = %d" , i );
printf( "\n l = %ld", l );
printf( "\n f = %f" , f );
printf( "\n d = %lf", d );
fclose(fe);
}
int main(void){
char fn[32] = "dados.txt";
escrever(fn);
ler(fn);
return 0;
}
Foram usadas funções para ler e escrever valores dos tipos string, char, int, long,
float e double, um de cada, em um arquivo dados.txt.

Escrevendo/lendo dados em arquivo binário.

Exemplo 4.103 Este programa escreve/lê dados em/de um arquivo binário.


#include <stdio.h>
#include <stdlib.h>
void escrever( char *fn ){
char c = 66;
int i = 67;
long l = 68;
float f = 69;
double d = 70;
FILE *fs = fopen( fn, "wb" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "Escrevendo valores" );
fwrite( fn, sizeof(char) , sizeof(fn), fs );
fwrite( &c , sizeof(char) , 1 , fs );
fwrite( &i , sizeof(int) , 1 , fs );
fwrite( &l , sizeof(long) , 1 , fs );
fwrite( &f , sizeof(float) , 1 , fs );
fwrite( &d , sizeof(double), 1 , fs );
fclose(fs);
Programação Básica com Linguagem C 191

}
void ler( char *fn ){
char c;
int i;
long l;
float f;
double d;
FILE *fe = fopen( fn, "rb" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "Lendo valores" );
fread( fn, sizeof(char) , sizeof(fn), fe );
fread( &c , sizeof(char) , 1 , fe );
fread( &i , sizeof(int) , 1 , fe );
fread( &l , sizeof(long) , 1 , fe );
fread( &f , sizeof(float) , 1 , fe );
fread( &d , sizeof(double), 1 , fe );

printf( "\n fn= %s" , fn);


printf( "\n c = %c" , c );
printf( "\n i = %d" , i );
printf( "\n l = %ld", l );
printf( "\n f = %f" , f );
printf( "\n d = %lf", d );

fclose(fe);
}
int main(void){
char fn[32] = "dados.bin";
escrever(fn);
ler(fn);
return 0;
}
Foram usadas funções para ler e escrever valores dos tipos string, char, int, long,
float e double, um de cada, em um arquivo dados.bin.

Escrevendo/lendo vetor de/em arquivo.

Exemplo 4.104 Este programa escreve/lê vetor em/de arquivo.


#include <stdio.h>
#include <stdlib.h>
void EscreverTexto( char *fn, int *X, int n ){
int i;
FILE *fs = fopen( fn, "w" );
Programação Básica com Linguagem C 192

if( fs == NULL){ puts("erro fopen"); exit(1); }


puts( "\nEscrevendo valores em arquivo texto" );
for( i = 0; i < n; i++ )
fprintf( fs, "%d ", X[i]+1 );
fclose(fs);
}
void LerTexto( char *fn, int *X, int n){
int i;
FILE *fe = fopen( fn, "r" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "\nLendo valores em arquivo texto" );
for( i = 0; i < n; i++ )
fscanf( fe, "%d ", &X[i] );
puts( "\nValores lidos de arquivo texto" );
for( i = 0; i < n; i++ )
printf( "%d ", X[i] );
fclose(fe);
}
void EscreverBinario( char *fn, int *X, int n){
FILE *fs = fopen( fn, "wb" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "\nEscrevendo valores em arquivo binario" );
fwrite( X, sizeof(int), n, fs );
fclose(fs);
}
void LerBinario( char *fn, int *X, int n){
int i;
FILE *fe = fopen( fn, "rb" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "Lendo valores de arquivo binario" );
fread( X, sizeof(int), n, fe );
puts( "\nValores lidos de arquivo binario" );
for( i = 0; i < n; i++ )
printf( "%d ", X[i] );
fclose(fe);
}
int main(void){
char txt[32] = "vetor.txt", bin [32] = "vetor.bin";
int N = 5, V[] = { 1, 2, 3, 4, 5 };
EscreverTexto(txt,V,N);
LerTexto(txt,V,N);
EscreverBinario(bin,V,N);
Programação Básica com Linguagem C 193

LerBinario(bin,V,N);
return 0;
}

Escrevendo/lendo estruturas de/em arquivo-texto.

Exemplo 4.105 Este código escreve uma estrutura em um arquivo-texto.


#include <stdio.h>
struct Aluno{
char nome[20];
char disciplina[20];
float nota[3];
float media;
};
int main(void){
FILE *f;
struct Aluno Pedro;
strcpy( Pedro.nome, "Pedro" );
strcpy( Pedro.disciplina, "Algoritmo" );
Pedro.nota[0] = 7.0;
Pedro.nota[1] = 8.0;
Pedro.nota[2] = 9.0;
f = fopen( "pedro.txt", "w" );
if( f == NULL){
puts("erro fopen");
exit(1); // encerra o programa e retorna ao SO com erro 1
}
fprintf(f,"\n Pedro" );
fprintf(f,"\n---------------------------------------");
fprintf(f,"\nPedro.nome : %s" , Pedro.nome );
fprintf(f,"\nPedro.disciplina: %s", Pedro.disciplina );
fprintf(f,"\nPedro.nota 1 : %f" , Pedro.nota[0] );
fprintf(f,"\nPedro.nota 2 : %f" , Pedro.nota[1] );
fprintf(f,"\nPedro.nota 3 : %f" , Pedro.nota[2] );
fprintf(f,"\nPedro.media : %f" , Pedro.media );
fprintf(f,"\n---------------------------------------");
fclose(f);
return 0;
}

Escrevendo/lendo estruturas de/em arquivo.

Exemplo 4.106 Este código escreve/lê estrutura em/de arquivo.


Programação Básica com Linguagem C 194

#include <stdio.h>
#include <stdlib.h>
struct Aluno{
char nome[20];
char disciplina[20];
float nota[3];
float media;
};
void EscreveTela( struct Aluno X ){
printf("\nNome: %-s", X.nome );
printf("\n---------------------------------------" );
printf("\nDisciplina: %-s" , X.disciplina );
printf("\nNota 1 : %.1f", X.nota[0] );
printf("\nNota 2 : %.1f", X.nota[1] );
printf("\nNota 3 : %.1f", X.nota[2] );
printf("\nMedia : %.1f", X.media );
printf("\n---------------------------------------" );
}
void EscreverTexto( char *fn, struct Aluno X ){
FILE *fs = fopen( fn, "w" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "\nEscrevendo valores em arquivo texto" );

fprintf(fs,"%s\n", X.nome );
fprintf(fs,"%s\n", X.disciplina );
fprintf(fs,"%f\n", X.nota[0]-0.5);
fprintf(fs,"%f\n", X.nota[1]-0.5);
fprintf(fs,"%f\n", X.nota[2]-0.5);
fprintf(fs,"%f\n", X.media -0.5);

fclose(fs);
}
void LerTexto( char *fn, struct Aluno X ){
FILE *fe = fopen( fn, "r" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "\nLendo valores em arquivo texto" );

fscanf(fe,"%s\n", &X.nome );
fscanf(fe,"%s\n", &X.disciplina );
fscanf(fe,"%f\n", &X.nota[0] );
fscanf(fe,"%f\n", &X.nota[1] );
fscanf(fe,"%f\n", &X.nota[2] );
Programação Básica com Linguagem C 195

fscanf(fe,"%f\n", &X.media );

puts( "\nValores lidos de arquivo texto" );


EscreveTela(X);
fclose(fe);
}
void EscreverBinario( char *fn, struct Aluno X ){
FILE *fs = fopen( fn, "wb" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "\nEscrevendo valores em arquivo binario" );
fwrite( &X, sizeof(struct Aluno), 1, fs );
fclose(fs);
}
void LerBinario( char *fn, struct Aluno X ){
FILE *fe = fopen( fn, "rb" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "Lendo valores de arquivo binario" );
fread( &X, sizeof(struct Aluno), 1, fe );
puts( "\nValores lidos de arquivo binario" );
EscreveTela(X);
fclose(fe);
}
int main(void){
char txt[32] = "struct.txt", bin [32] = "struct.bin";

struct Aluno Pedro;


strcpy( Pedro.nome, "Pedro" );
strcpy( Pedro.disciplina, "Algoritmo" );
Pedro.nota[0] = 7.0;
Pedro.nota[1] = 8.0;
Pedro.nota[2] = 9.0;
Pedro.media = 8.5;

EscreveTela(Pedro);

EscreverTexto (txt,Pedro);
LerTexto (txt,Pedro);
Pedro.media = 6.5; // testando escrita e leitura
EscreverBinario(bin,Pedro);
LerBinario (bin,Pedro);

return 0;
Programação Básica com Linguagem C 196

Todos os arquivos são fechados automaticamente quando o programa é


encerrado normalmente. No entanto, é fortemente recomendável que se feche um
arquivo aberto assim que não for mais necessário.

Abrindo e Fechando Arquivos

Pense em Arquivo como armário ou guarda-roupa.


Para manipular o armário é necessário abri-lo.
Uma vez aberto, pode-se colocar coisas lá dentro, tirar coisas lá de
dentro. Fazer uma limpeza antes de colocar novas coisas. Eliminar tudo
que está dentro dele. E outras operações que nem imagino.
Mas, ao final, o armário tem que ser fechado.
Esquecer o armário aberto pode ter consequências imprevisíveis ao
longo do tempo, entrar/sair coisas indesejadas, por exemplo.

4.11.4. Arquivos stdin, stdout e stderr


A linguagem C define em stdio.h os arquivos padrão para entrada, saída e saída
de erro:

FILE *stdin , // entrada padrão - teclado


*stdout, // saída padrão - vídeo
*stderr, // erro padrão - vídeo
*stdaux, // primeira porta serial
*stdprn; // impressora

A entrada padrão é via teclado, enquanto a saída padrão e erro padrão são
impressos na saída de vídeo.

printf( Comandos ) é o mesmo que fprintf( stdout, Comandos );


scanf ( Comandos ) é o mesmo que fscanf ( stdin , Comandos );

4.11.5. Tratamento de Erros


A linguagem C não fornece suporte direto para o tratamento de erros, mas
fornece acesso aos erros na forma de valores de retorno. Para prover informações
de erros ocorridos no programa, é declarada a variável global errno em errno.h. Em
caso de erro, a maioria das chamadas de função C retornam -1 ou NULL mas,
também atribuí a errno o código do erro se ele for tratado pela linguagem C. Ela
ainda fornece as funções perror e strerror podem ser usadas para exibir a
mensagem de texto associada ao erro:

a) perror - exibe a string que o programador passa para ela, dois pontos e espaço,
seguida da representação textual do valor atual do erro
Programação Básica com Linguagem C 197

b) strerror - retorna um ponteiro para a representação textual do valor atual do erro

Exemplo 4.107 Este código mostra o uso de errno e das funções perror e strerror.
#include <stdio.h>
#include <errno.h>
#include <string.h>

extern int errno;

int main ( void ){


FILE *fs = fopen( "inexistente.txt", "rb" );
if( fs == NULL ){
int errnum = errno;
fprintf( stderr, "Valor do errno: %d\n", errno );
perror ( "Erro informado por perror" );
fprintf( stderr, "Erro de arquivo: %s\n", strerror(errnum));
}
fclose(fs);
return 0;
}

Exemplo 4.108 Este código mostra o uso das funções feof e getc.
#include <stdio.h>
#include <stdlib.h>
int main( void )
char ch;
FILE *fe = fopen("texto.txt","w"); // não testa fe == NULL
while( !feof(fe) ){
ch = getc(fe);
putchar( ch );
}
fclose(fe);
return 0;
}

Exemplo 4.109 Este código mostra o uso das funções ferror, fwrite e fread.
#include<stdio.h>
#include<stdlib.h>
Programação Básica com Linguagem C 198

#define MAX 12
int main( void ){
int l;
float v[MAX], w[MAX];

for( l = 0; l < MAX; l++ )


v[l] = rand() % MAX;

printf( "\n v:" );


for( l = 0; l < MAX; l++ )
printf( "%f", v[l] );

FILE *f = fopen( "f5.txt", "w+" );

if( ferror(f) ) exit(1);

fwrite( v, sizeof(float), MAX, f );


rewind( f );
fread ( w, sizeof(float), MAX, f );

printf( "\n w:" );


for( l = 0; l < MAX; l++ )
printf( " %.0f ", w[l] );

fclose(f);

return 0;
}

4.11.6. Resumo
Programação Básica com Linguagem C 199

Figura 4.32 Mapa mental de Arquivo.

4.11.7. Exercícios

1. Faça um programa C para escrever uma matriz em um arquivo-texto. Faça um outro


programa C para ler a matriz previamente escrita em um arquivo-texto.
2. Faça um programa C para escrever uma matriz em um arquivo binário. Faça um
outro programa C para ler a matriz previamente escrita em um arquivo binário.
3. Faça uma função que recebe uma matriz e retorne uma string com os dados da
matriz no formato de tabela html5.
4. Faça um programa para copiar arquivos, seus dados de entrada são nome do arquivo
original e nome do arquivo para cópia.
Programação Básica com Linguagem C 200

5. Alocação Dinâmica de Memória

5.1. Memória Principal


A memória RAM (Random Access Memory – Memória de Acesso Aleatório) de
qualquer computador é uma sequência de bytes (B). Um computador de 4 GB
possui 4x1024x1024x1024 B = 4.294.967.296 B, numerados de 0 a 4.294.967.295,
de 0000000016 a 0xFFFFFFFF16 em hexadecimal.

Figura 5.1 Memória do computador, organização, endereço e octeto.

Seja N o número de bytes de uma memória RAM, logo os bytes desta memória
são numerados de 0 a N–1. Hoje em dia o valor de N é muito grande e tende a
aumentar com o passar dos anos.
Os endereços de memória são numerados a partir de zero, utilizando números
inteiros sem sinal. Normalmente, para expressar o tamanho da memória, utiliza-se
os tipos unsigned int ou unsigned long int. O tamanho da memória é muito
grande, dado em GB – Giga Byte, TB – Tera Byte ou PB – Peta Byte.
Cada uma das variáveis de um programa de computador ocupa um número de
bytes consecutivos na memória do computador. Uma variável do tipo char ocupa 1
B. Uma variável do tipo int ocupa 4 B e um double ocupa 8 B em muitos
computadores – estes valores dependem da arquitetura do hardware.
Programação Básica com Linguagem C 201

O número exato de bytes de uma variável é dado pelo operador sizeof. A


expressão sizeof (char), por exemplo, vale 1 em todos os computadores e a
expressão sizeof (int) vale 4 em muitos computadores.

Exemplo 5.1 Imprimir o número exato de bytes de variáveis de alguns tipos


utilizando o operador sizeof.
#include <stdio.h>
int main( void ){
printf("\n\n\n");
printf("\n sizeof(char) = %2d", sizeof( char) );
printf("\n sizeof(int) = %2d", sizeof( int) );
printf("\n sizeof(long) = %2d", sizeof( long) );
printf("\n sizeof(float) = %2d", sizeof( float) );
printf("\n sizeof(double) = %2d", sizeof( double) );
printf("\n sizeof(long double)= %2d", sizeof(long double) );
printf("\n\n\n");
return 0;
}

Exemplo 5.2 Imprimir formatado o número exato de bytes de variáveis dos tipos
utilizando o operador sizeof.
#include <stdio.h>
int main( void ){
printf("\n ----------------------");
printf("\n x sizeof(x) ");
printf("\n ----------------------");
printf("\n char %2d", sizeof( char) );
printf("\n int %2d", sizeof( int) );
printf("\n long %2d", sizeof( long) );
printf("\n float %2d", sizeof( float) );
printf("\n double %2d", sizeof( double) );
printf("\n long double %2d", sizeof( long double) );
printf("\n ----------------------");
printf("\n\n\n");
return 0;
}

5.2. Programas C e Memória Principal


O recurso de destaque da Linguagem C é a capacidade de manipular
diretamente a memória dos seus programas sem a interferência do Sistema
Programação Básica com Linguagem C 202

Operacional. Programas C podem reservar uma parte da memória da máquina para


seu uso exclusivo, este recurso é conhecido como Alocação Dinâmica da Memória.
O Sistema Operacional, ao carregar um programa executável, atribui uma Pilha
de Chamada para este programa, é a sua memória de trabalho.
A Pilha de Chamada é organizada em quatro regiões da memória RAM
logicamente distintas. Embora o layout físico destas regiões diferem entre os tipos
de Sistemas Operacionais, a descrição a seguir mostra conceitualmente como
Programas C utilizam sua memória de trabalho, Figura 5.2:

1. Heap – exclusiva para alocação dinâmica da memória, o seu tamanho pode


aumentar ou diminuir de acordo com o uso, o seu limite é a memória disponível na
máquina, por isso é chamada de memória livre
2. Stack – exclusiva para as variáveis locais, funções e seus parâmetros
3. Global – exclusiva para as variáveis globais e variáveis estáticas
4. Program Code - exclusiva para armazenar os comandos do programa em execução

O Heap é gerenciado pelo programa em execução e a Linguagem C possui as


funções malloc, calloc, realloc e free para este fim. As demais regiões (Stack, Global
e Program Code) são gerenciadas pelo Sistema Operacional.

Figura 5.2 Pilha de Chamada C.

A região Heap pode ser usada dinamicamente pelo programa executável, por
meio de apontadores, e sem a interferência do Sistema Operacional. A memória
que não é gerenciada automaticamente, o programa em execução deve alocar e
liberar toda memória que usar. Deixar de liberar a memória ao terminar de usá-la é
um erro conhecido como vazamento de memória – memória que não é usada pelo
programa que a alocou e não fica disponível para outros processos. O tamanho do
Heap está limitado ao tamanho da memória física disponível na máquina.
Resumo do Heap:

• ela é gerenciada pelo programador


• as variáveis nela alocadas e liberadas usam funções como malloc() e free()
Programação Básica com Linguagem C 203

• ela é grande e geralmente é limitada pela memória física disponível


• ela requer apontadores para acessá-la
• seu mau gerenciamento pode causar vazamento de memória

Funções da Linguagem C para gerenciamento do Heap:

• malloc() - usada para alocar um novo bloco de memória para uso exclusivo do
programa executável. Pode ocorrer falha na alocação, escrever fora do bloco alocado
• calloc() - usada para alocar um novo bloco de memória para uso exclusivo do
programa executável, como malloc porém escreve 0 em todos os bits alocados.
• realloc() - usada para realocar um bloco de memória previamente alocado por malloc
ou calloc. Pode ocorrer falha na realocação.
• free() - libera a memória previamente alocada ou realocada. Pode ocorrer falha na
liberação da memória e, como consequência, o Sistema Operacional perde o controle
da memória alocada ao fim do programa executável

A região Stack é usada para armazenar parâmetros de funções e variáveis


declaradas em funções, incluindo a função main. Cada vez que uma função declara
uma nova variável, ela é alocada na Stack. Ao término das funções, todas as
variáveis nelas declaradas são excluídas da pilha e a memória que elas usavam é
liberada para o SO. A Stack é uma região especial da memória é e gerenciada
automaticamente pelo SO e, logo, não ocorrem erros de alocação ou liberação de
memória. O tamanho da pilha varia entre os SO’s. No entanto, pode ocorrer erro de
estouro de Stack, quando o programa em execução tenta usar mais memória do
que aquela disponível na Stack. Este erro é comum em funções recursivas mal
comportadas.
Resumo do Stack:

• é gerenciada pelo SO, não pode ser modificada pelo programa em execução
• as variáveis nela alocadas pelo SO são liberadas automaticamente
• ela não é ilimitada, possui um limite superior
• ela aumenta e diminui conforme as variáveis são criadas e destruídas
• suas variáveis existem enquanto a função que as declarou existir
• seu mau uso pode causar estouro de pilha

estouro de Stack – ocorre quando o programa tentar usar mais


memória do que aquela disponível (na Stack)
vazamento de memória – causado pelo mau gerenciamento do
Heap
Programação Básica com Linguagem C 204

Pesquise na wikipédia: pilha de chamada

5.3. Alocação de Memória


A alocação estática ocorre em tempo de compilação, ou seja, a memória para as
variáveis é reservada e fica disponível durante o tempo de execução.
A alocação dinâmica ocorre em tempo de execução, ou seja, nenhuma memória
para as variáveis é reservada. Se uma variável precisar então sua memória é
reservada. E, ao finalizar seu uso, sua memória é liberada.
A alocação dinâmica da memória dos Programas C é feita pelo programador,
codificada em seu programa-fonte. O Heap, ou área de alocação dinâmica, está
disponível para uso do programa. A Biblioteca Padrão <stdlib.h> oferece um
conjunto de funções que permite a alocação e liberação dinâmica de memória.

Tabela 5.1 Funções C para manipulação da memória de forma dinâmica


Função Descrição
void *malloc(size_t) alocar um bloco de memória de tamanho size_t
void *calloc(size_t,size_t) alocar um bloco de memória de tamanho size_t
void *realloc(void*,size_t) redimensionar blocos de memória
void free (void *) liberar um bloco de memória
As funções malloc, calloc e realloc retorna um ponteiro para a início do bloco
alocado ou redimensionado. Tanto realloc quanto free requerem o endereço do
bloco previamente alocado.18
A função calloc, além de fazer a mesma coisa que malloc, ela zera o bloco de
memória alocado, ou seja, ela escreve o byte 0 em todas posições de memória
alocadas.
Estas funções podem falhar por diversas razões. No caso de falha estas funções
retornam o ponteiro NULL e, assim recomenda–se um teste de falha.
A Linguagem C não possui um gerenciamento automático do Heap. Como
consequência, o próprio programa deve liberar suas memórias alocadas.

Exemplo 5.3 Vetor dinâmico


#include<stdio.h>
#define MAX 10
int main( void ){
int *p, i;
puts("\n Alocando memoria\n");
p = (int*) malloc( MAX*sizeof(int) );
if( p == NULL ) exit(1);
for( i = 0; i < MAX; i++ )

18 O tipo size_t é um inteiro sem sinal, usado para endereços da memória principal ou endereços de hardware.
Programação Básica com Linguagem C 205

p[i] = rand() % MAX;


for( i = 0; i < MAX; i++ )
printf( "%d, ", p[i] );
puts("\n Liberando a memoria alocada.");
free(p);
return 0;
}

Exercício 5.1 Refaça o Exemplo 5.3 usando função realloc para dobrar o tamanho
da memória por p.
Exercício 5.2 Refaça o Exemplo 5.3 usando os tipos long e double.

5.4. Vetores Estático x Dinâmico


Vetores estáticos são declarados com tamanho predefinidos. O compilador
aloca o seu espaço na memória de forma automática. Diz-se que a alocação
estática é feita em tempo de compilação.
Vetores dinâmicos são apontadores e seu tamanho é definido ao alocar memória
para ele, que é feita de forma dinâmica. Diz-se que a alocação dinâmica é feita em
tempo de execução. Neste caso, o espaço em memória é alocado apenas quando
necessário.

Exemplo 5.4 Exemplo de vetores estático e dinâmico.


#include <stdio.h>
#define n 5
int main( void ){
int c,
*p, // p é apontador para tipo int
V[n] = { 1, 2, 3, 4, 5 }; // V é um vetor estático
for( c = 0; c < n; c++ )
printf(" %d ", V[c] );
return 0;
}

Exemplo 5.5 Exemplo de vetores estático de tipo int.


#define n 5
int main( void ){
int c, V[n] // V é um vetor estático
Programação Básica com Linguagem C 206

for( c = 0; c < n; c++ ) // atribuição de valores


V[c] = rand() % 10;
for( c = 0; c < n; c++ )
printf(" %d ", V[c] );
return 0;
}

Exemplo 5.6 Exemplo de vetor dinâmico de tipo int.


#include <stdio.h>
#define n 5
int main( void ){
int c, *V; // V é apontador para tipo int
V = (int*) malloc( n*sizeof(int) ); // alocação de memória
for( c = 0; c < n; c++ ) // atribuição de valores
V[c] = rand() % 10;
for( c = 0; c < n; c++ )
printf(" %d ", V[c] );
free(V); // liberação de memória
return 0;
}
Os vetores dinâmicos requerem algoritmo mais elaborados, sendo necessário a a locação
dinâmica de memória e sua posterior liberação (não foi testado de V é NULL).

5.5. Vetor de Apontadores


Apontadores podem ser agrupados em um vetor, a declaração abaixo cria um
vetor com 10 apontadores para tipo int:

int *x[10];

Exemplo 5.7 Uso de vetor de apontadores para tipo int.


#include <stdio.h>
#define n 5
int main( void ){
int c,
*p[n],
v[n] = { 4, 5, 1, 3, 6 };

for( c = 0; c < n; c++ )


p[c] = &v[c];
Programação Básica com Linguagem C 207

for( c = 0; c < n; c++ )


printf(" %d ", *p[c] );
return 0;
}
Neste exemplo, ao apontar p para v, índice por índice, foi possível imprimir v a
partir de p.
p[0] p[1] p[2] p[3] p[4]
↓ ↓ ↓ ↓ ↓
v[0] v[1] v[2] v[3] v[4]

Exercício 5.3 Aumente os valores de L dos Algoritmos 1 e 2 aos poucos. Como


explicar o comportamento destes dois algoritmos? Relacione com a Erro: Origem
da referência não encontrada.

Algoritmo 1
============================================
#include <stdio.h>
#include <stdlib.h>
#define L 1000
int main( void ){
double A[L][L];
printf("Tamanho de A é %ld bytes", L*L*sizeof(double) );
return 0;
}

Algoritmo 2
============================================
#include <stdio.h>
#include <stdlib.h>
#define L 1000
double **Criar( void ){
int l;
double **X;
X = (double**) malloc( L*sizeof(double*) );
for( l = 0; l < L; l++ )
X[l] = (double*) malloc( L* sizeof(double) );
return X;
}
void Destruir( double **X ){
int l;
Programação Básica com Linguagem C 208

for( l = 0; l< L; l++ )


free(X[l]);
free(X);
}
int main( void ){
double **A;
printf("Tamanho de A é %ld bytes", L*L*sizeof(double) );
A = Criar();
Destruir(A);
return 0;
}

Matriz e Apontador

Exemplo 5.8 Programa em C para multiplicar duas matrizes C=AB, para quaisquer
valores de m, n e p, sem variáveis globais, com menor número de funções
possível, sem blocos de comandos repetidos, com valores das matrizes gerados
aleatoriamente e com a main "menor" possível.
#include <stdio.h>
#define Nl 3
#define Nc 4

int main( void ){


int l, c;
double **A;

// alocar os elementos de A, criar memória para A


A = (double**) malloc( Nl *sizeof(double*) );
for( l = 0; l < Nl; l++ )
A[l] = (double*) malloc( Nc * sizeof(double) );
if( A == NULL ){ puts("erro de alocacao"); exit(1);}

// atribuir dados aleatórios para A


for( l = 0; l < Nl; l++ )
for( c = 0; c < Nc; c++ ){
A[l][c] = rand() % 100;

printf("Imprimindo A " );
for( l = 0; l < Nl; l++ ){
printf("\n");
Programação Básica com Linguagem C 209

for( c = 0; c < Nc; c++ )


printf(" %lf ", A[l][c] );
}

// dealocar os elementos de A, destrui A


for( l = 0; l < Nl; l++ )
free(A[l]);
free(A);
return 0;
}

Multiplicar duas matrizes

Exemplo 5.9 Programa em C para multiplicar duas matrizes C=AB, para quaisquer
valores de m, n e p, sem variáveis globais, com menor número de funções
possível, sem blocos de comandos repetidos, com valores das matrizes gerados
aleatoriamente e com a main "menor" possível.
#include <stdio.h>
#define M 3
#define N 4
#define P 3
double **Criar( int Lin, int Col ){
int i;
double **X;
X = (double**) malloc( Lin*sizeof(double*) );
for( i = 0; i < Lin; i++ )
X[i] = (double*) malloc( Col* sizeof(double) );
if( X == NULL ){ puts("erro de alocacao"); exit(1);}
return X;
}
void Destruir( double **X, int Lin ){
int i;
for( i = 0; i < Lin; i++ )
free(X[i]);
free(X);
}
void Ler( char c, double **V, int Lin, int Col ){
int i, j;
printf( "\n\n\n Leitura de %c ", c );
for( i = 0; i < Lin; i++ )
for( j = 0; j < Col; j++ ){
printf(" De o valor de %c[%d][%d]: ", c, i, j );
scanf("%lf", &V[i][j] );
Programação Básica com Linguagem C 210

}
}
void Calculo( double **A, double **B, double **C ){
int i, j, r;
printf("\n\n\n Calculando C = AB … " );
for( i = 0; i < M; i++ )
for( j = 0; j < P; j++ ){
C[i][j] = 0.0;
for( r = 0; r < N; r++ )
C[i][j] = A[i][r]*B[r][j];
}
}
void Escrever( char c, double **X, int Lin, int Col ){
int i, j;
printf("\n\n\n Imprimindo %c ", c );
for( i = 0; i < Lin; i++ ){
printf("\n");
for( j = 0; j < Col; j++ )
printf(" %lf ", X[i][j] );
}
}
int main( void ){
double **A, **B, **C;
A = Criar(M,N);
B = Criar(N,P);
C = Criar(M,P);
Ler('A',A,M,N);
Ler('B',B,N,P);
Escrever('A',A,M,N);
Escrever('B',B,N,P);
Calculo(A,B,C);
Escrever('C',C,M,P);
Destruir(A,M);
Destruir(B,N);
Destruir(C,P);
return 0;
}

Struct e Apontador
Programação Básica com Linguagem C 211

Exemplo 5.10 Programa de vetor de struct com alocação dinâmica. Compare este
exemplo com o anterior, identifique e explique as diferenças.
# include <stdio.h>
# define TAM 3
struct Aluno{
char nome[12];
char disciplina[12];
float nota[3];
float media;
};
struct Aluno *Criar( void ){
struct Aluno *A;
A = (struct Aluno*) malloc( TAM*sizeof(struct Aluno) );
if( A == NULL ){
puts("Erro ao criar Aluno");
abort();
}
return A;
}
void Ler( struct Aluno *T ){
printf("\n Nome:" ); scanf("%s", T->nome );
printf("\n Disciplina:" ); scanf("%s", T->disciplina );
printf("\n Primeira nota:" ); scanf("%f", T->nota );
printf("\n Segunda nota:" ); scanf("%f", T->nota+1 );
printf("\n Terceira nota:" ); scanf("%f", T->nota+2 );
T->media = ( T->nota[0]+T->nota[1]+T->nota[2] )/3.0;
}
int main(void){
int c;
struct Aluno *Turma;
Turma = Criar();
for( c = 0; c < TAM; c++ ){
printf("\n Aluno: %d", c+1 );
Ler(Turma+c);
}
printf( "\n================================================");
printf( "\n No Nome Disciplina Nota 1 Nota 2 Nota 3 Media ");
printf( "\n------------------------------------------------");
for( c = 0; c < TAM; c++ ){
printf("\n");
printf(" %2d", c+1 );
printf(" %-12s", Turma[c].nome );
Programação Básica com Linguagem C 212

printf(" %-12s", Turma[c].disciplina );


printf(" %6.1f", Turma[c].nota[0] );
printf(" %6.1f", Turma[c].nota[1] );
printf(" %6.1f", Turma[c].nota[2] );
printf(" %6.1f", Turma[c].media );
}
printf( "\n================================================");
free(Turma);
return(0);
}

Escrevendo/lendo matriz de/em arquivo.

Exemplo 5.11 Este programa escreve/lê dados em/de arquivo


#include <stdio.h>
#include <stdlib.h>
int **Aloca( int nl, int nc ){
int **X, l, c;
X = (int**)malloc(nl*sizeof(int*));
for( l = 0; l < nl; l++ )
X[l] = (int*)malloc( nc*sizeof(int));

puts( "\nValores alocados e atribuidos" );


for( l = 0; l < nl; l++ ){
printf("\n");
for( c = 0; c < nc; c++){
X[l][c] = l+c;
printf( "%d ", X[l][c] );
}
}
return X;
}
void DeAloca( int **X, int nl ){
int l;
for( l = 0; l < nl; l++ )
free(X[l]);
}
void EscreverTexto( char *fn, int **X, int nl, int nc ){
int l, c;
FILE *fs = fopen( fn, "w" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "\nEscrevendo valores em arquivo texto" );
for( l = 0; l < nl; l++ )
Programação Básica com Linguagem C 213

for( c = 0; c < nc; c++ )


fprintf( fs, "%d ", X[l][c]+1 );
fclose(fs);
}
void LerTexto( char *fn, int **X, int nl, int nc ){
int l, c;
FILE *fe = fopen( fn, "r" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "\nLendo valores em arquivo texto" );
for( l = 0; l < nl; l++ )
for( c = 0; c < nc; c++ )
fscanf( fe, "%d ", &X[l][c] );
puts( "\nValores lidos de arquivo texto" );
for( l = 0; l < nl; l++ ){
printf("\n");
for( c = 0; c < nc; c++ )
printf( "%d ", X[l][c] );
}
fclose(fe);
}
void EscreverBinario( char **fn, int *X, int nl, int nc ){
FILE *fs = fopen( fn, "wb" );
if( fs == NULL){ puts("erro fopen"); exit(1); }
puts( "\nEscrevendo valores em arquivo binario" );
fwrite( X, sizeof(int), nl*nc, fs );
fclose(fs);
}
void LerBinario( char *fn, int **X, int nl, int nc ){
int l, c;
FILE *fe = fopen( fn, "rb" );
if( fe == NULL){ puts("erro fopen"); exit(1); }
puts( "Lendo valores de arquivo binario" );
fread( X, sizeof(int), nl*nc, fe );
puts( "\nValores lidos de arquivo texto" );
for( l = 0; l < nl; l++ ){
printf("\n");
for( c = 0; c < nc; c++ )
printf( "%d ", X[l][c] );
}
fclose(fe);
}
int main(void){
Programação Básica com Linguagem C 214

char txt[32] = "matriz.txt", bin [32] = "matriz.bin";


int nl = 4, nc = 5, **M = Aloca(nl,nc);
EscreverTexto (txt,M,nl,nc);
LerTexto (txt,M,nl,nc);
EscreverBinario(bin,M,nl,nc);
LerBinario (bin,M,nl,nc);

DeAloca(M,nl);
return 0;
}

5.6. Resumo

Figura 5.3 Mapa mental de Alocação Dinâmica.

Estude o Capítulo 5 – Ponteiros.


Programação Básica com Linguagem C 215

garbage–collection – é um mecanismo de controle automático de


alocação e liberação de memória

Recebendo e Devolvendo Memória

Pense na locação da memória como um empréstimo que, ao final, tem


que ser devolvido integralmente.
A memória é um recurso da máquina, de tamanho limitado, que pode
ser empresta aos programas.
Os programas usam malloc ou calloc para obter memória emprestada.
Os programas podem ampliar ou reduzir este empréstimo usando
realloc.
Os programas usam free para devolver memória emprestada.
Se os programas não devolverem as memórias emprestadas, vai faltar
este recurso para emprestar a outros programas. A máquina vai ficar
sem memória é pode vir a falhar.
Programação Básica com Linguagem C 216

6. Biblioteca Padrão C

A Biblioteca Padrão C (glibc) é um conjunto funções que contém operações


comuns de todos os Programas C. Estas funções são agrupadas cabeçalhos. A
nomenclatura e o escopo dos cabeçalhos é comum a diferentes implementações.
Na Tabela 6.1 estão os cabeçalhos da Biblioteca Padrão ANSI C.

Tabela 6.1 Cabeçalhos da Biblioteca Padrão ANSI C


Cabeçalho Descrição
Macro para ajudar na detecção de erros lógicos e outros tipos de erros em versões de
<assert.h>
depuração de um programa
<complex.h> Conjunto de funções para manipular números complexos
Funções usadas para classificar caracteres pelo tipo ou para converter entre caixa alta e baixa
<ctype.h>
independentemente da codificação
<errno.h> Teste de códigos de erro reportados pelas funções de bibliotecas
<fenv.h> Controle de ponto flutuante
Constantes de propriedades específicas de implementação da biblioteca de ponto flutuante,
como a menor diferença entre dois números de ponto flutuante distintos (_EPSILON), a
<float.h>
quantidade máxima de dígitos de acurácia (_DIG) e a faixa de números que pode ser
representada (_MIN, _MAX)
<inttypes.h> Conversão precisa entre tipos inteiros
<iso646.h> Programação na codificação de caracteres ISO 646
Constantes de propriedades específicas de implementação da biblioteca de tipos inteiros,
<limits.h>
como a faixa de números que pode ser representada (_MIN, _MAX)
<locale.h> Constantes para setlocale() e assuntos relacionados
<math.h> Funções matemáticas comuns em computação
<setjmp.h> Macros setjmp e longjmp, para saídas não locais
<signal.h> Tratamento de sinais
<stdarg.h> Acesso dos argumentos passados para funções com parâmetro variável
<stdbool.h> Definição do tipo de dado booleano
<stdint.h> Definição de tipos de dados inteiros
<stddef.h> Diversos tipos e macros úteis
<stdio.h> Manipulação de entrada/saída
Diversas operações, incluindo conversão, geração de números pseudo–aleatórios, alocação de
<stdlib.h>
memória, controle de processo, sinais, busca e ordenação
<string.h> Tratamento de cadeia de caracteres
<tgmath.h> Funções matemáticas
<time.h> Conversão de tipos de dado de data e horário
<wchar.h> Manipulação de caractere wide, usado para suportar diversas línguas
<wctype.h> Classificação de caracteres wide
Programação Básica com Linguagem C 217
Programação Básica com Linguagem C 218

7. Aplicações

7.1. Máximo Divisor Comum MDC


O MDC de dois ou mais números inteiros é o maior divisor inteiro comum a todos
eles. Por exemplo, o m.d.c. de 16 e 36 é 4, e denotamos isso por MDC(16,36)=4. Já
o MDC(30, 54, 72)=6.
O algoritmo de Euclides permite calcular o MDC de dois números. Sejam a e b
dois números naturais não nulos, a > b. O passo a passo deste algoritmo é:

1. Divide-se o maior número, a, pelo menor, b, obtendo resto o r 0


2. Divide-se b por r0 , obtendo o resto r1
3. Divide-se r 0 por r1 , obtendo o resto r2
4. E assim, sucessivamente, divide-se r i-1 por ri, obtendo o resto ri+1
5. Até obter o primeiro resto 0, logo MDC(a,b) = r i-1

Exemplo 7.1 Função para calcular o mdc.


#include <stdio.h>
typedef unsigned int uint;
uint mdc( int a, int b ){
uint r;
do{
r = a % b;
a = b;
b = r;
}while( r != 0 );
return a;
}
int main( void ){
uint a = 72, b = 30;
if( b > a ){
uint m = a;
a = b;
Programação Básica com Linguagem C 219

b = m;
}
printf(" mdc( %u, %u ) = %u", a, b, mdc(a,b) );
return 0;
}

7.2. Números Primos


Os números primos são os números naturais que têm apenas dois divisores, 1 e
ele mesmo.

número primo – número naturai que têm apenas dois divisores, 1 e


ele mesmo.

Para saber se um número é primo, dividimos esse número pelos números primos
2, 3, 5, 7, 11, etc, até que tenhamos:

• ou uma divisão com resto zero (e neste caso o número não é primo),
• ou uma divisão com quociente menor que o divisor e o resto diferente de zero, neste
caso o número é primo

Para encontrar números primos, utiliza-se o Crivo de Eratóstenes: uma tabela


com os números de 1 a N. Nesta tabela são cancelados os números que não são
primos seguindo esta ordem:

• O número 1 estará fora, pois os números primos são maiores que um


• Os números terminados em 0, 2, 4, 6 e 8 estarão fora porque são divisíveis por dois
• Os números terminados em 5 estarão fora porque são divisíveis por 5.
• Os números terminados em zero já foram cortados
• Os números cuja soma dos algarismos for 3 estarão fora por serem divisíveis por três
• Os números que são divisíveis por 7 serão retirados também
• E assim por diante, até N/2

Exemplo 7.2 Função para identificar número é primo.


A função primo identifica se N é primo, consiste em dividir todos os números entre
1 e N, ambos incluídos, e contar as divisões exatas, ou seja, aquelas cujo resto é
zero.
O número primo N é divisível por 1 e N (ele mesmo) e por nenhum outro número
do intervalo, assim a contagem de divisões exatas é igual a dois.
O número não primo (composto) N é divisível por 1 e N (ele mesmo) e por algum
outro número do intervalo, assim a contagem divisões exatas é maior do que dois.
#include <stdio.h>
Programação Básica com Linguagem C 220

#include<stdbool.h>
typedef unsigned int uint;
bool primo( uint N ){
uint i, div = 0;
for( i = 1; i <= N; i++ )
if( N % i == 0 ) div++;
if( div == 2 ) return 1;
else return 0;
}
int main( void ){
uint N = 17;
if( primo(N) ) printf( " N = %d e primo", N );
else printf( " N = %d não e primo", N );
return 0;
}
Há muitos algoritmos sobre números primos, este é apenas um deles, embora
didático é ineficiente.

7.3. Aplicações com Séries


Séries são úteis para aproximação de funções, integração numérica, resolução
de problemas de Engenharia de modo geral. Dentre as diversas séries matemáticas,
pode-se destacar as seguintes:

1 2 3 4 5

n
1. =1+ x + x + x + x + x +⋯=∑ x para |x| < 1.
1−x n=0
n
π = (−1) =1− 1 + 1 − 1 +⋯

2. ∑
4 n=1 2 n+1 3 5 7

1
3. e=∑
n=0 n !

xn
4. e x =∑
n=0 n!

(−1)n 2 n +1
5. sen ( x)=∑ x
n=0 (2 n+1)!
∞ n
(−1) 2 n
6. cos( x)=∑ x
n=0 (2n) !


A fórmula geral de uma série é S=∑ ui , ou seja, S=u 0+ u1+ u2+ u3 +u4 +⋯ .
i=0
1 ∞
1 1 1 1
Considere obter a série S=∑ 2i
, ou seja, S=1+ 2 + 4 + 6 + 8 +⋯ . Esta soma é
i=0 x x x x x
infinita e não tem como calcular seu valor exato por meio de algoritmo. Como foi
Programação Básica com Linguagem C 221

visto, algoritmos precisam ser finitos.


Como as séries são muito úteis nas engenharias, foram desenvolvidos métodos
e técnicas para aproximação de séries infinitas, que consiste em calculá-las de
modo aproximado. No quadro abaixo, pode-se ver os valores de, i, u i, 1/x2i e S, para
x= 0,5.
i ui 1/x2i Si
0 u0 1,0000000 1,0000000
1 u1 0,2500000 1,2500000
2 u2 0,0625000 1,3125000
3 u3 0,0156250 1,3281250
4 u4 0,0039063 1,3320313
5 u5 0,0009766 1,3330078
6 u6 0,0002441 1,3332520
7 u7 0,0000610 1,3333130
8 u8 0,0000153 1,3333282
9 u9 0,0000038 1,3333321
10 u10 0,0000010 1,3333330
11 u11 0,0000002 1,3333333
12 u12 0,0000001 1,3333333
13 u13 0,0000000 1,3333333
14 u14 0,0000000 1,3333333
15 u15 0,0000000 1,3333333
16 u16 0,0000000 1,3333333
Pode-se verificar que basta somar os primeiros 13 termos desta série para se
obter seu valor aproximado com 7 casas decimais.
Observe que a medida que o valor de i aumenta, o valor das parcelas
correspondentes diminuem. A partir de i = 13, as parcelas não mais contribuem
com a soma. Sendo assim, basta obter a série para i de 0 a 12.

Observe que diferença entre as somas ΔSi = Si – Si-1 = ui. Pode-se usar ui como
critério de parada do algoritmo.
2 i+1 3 5 7

x x x x
Considere obter a série S=∑ (−1)i , ou seja, S=x− − + +⋯ . No
i=0 2 i+ 1 3 5 7
quadro abaixo, pode-se ver os valores de, i, ui, (-1) x /(2i+1) e S, para x= 0,7.
i 2i+1

i ui (-1)ix2i+1/(2i+1) S
0 u0 0,7000000 0,7000000
1 u1 -0,1143333 0,5856667
2 u2 0,0336140 0,6192807
3 u3 -0,0117649 0,6075158
4 u4 0,0044837 0,6119995
5 u5 -0,0017976 0,6102019
6 u6 0,0007453 0,6109472
7 u7 -0,0003165 0,6106307
8 u8 0,0001368 0,6107676
9 u9 -0,0000600 0,6107076
10 u10 0,0000266 0,6107342
11 u11 -0,0000119 0,6107223
12 u12 0,0000054 0,6107276
13 u13 -0,0000024 0,6107252
14 u14 0,0000011 0,6107263
15 u15 -0,0000005 0,6107258
16 u16 0,0000002 0,6107260
17 u17 -0,0000001 0,6107259
18 u18 0,0000001 0,6107260
Programação Básica com Linguagem C 222

19 u19 0,0000000 0,6107260


20 u20 0,0000000 0,6107260
Pode-se verificar que basta somar os primeiros 19 termos desta série para se
obter seu valor aproximado com 7 casas decimais.
Observe que a medida que o valor de i aumenta, o valor das parcelas
correspondentes diminuem mas alternam seu sinal, ora positivo ora negativo. A
partir de i = 19, as parcelas, positivas ou negativas, não mais contribuem com a
soma. Sendo assim, basta obter a série para i de 0 a 18.
As séries, de modo geral, seguem este padrão. Os matemáticos e cientistas da
computação já identificaram as séries que podem ser tradadas por métodos
computacionais. Estes métodos são extensivamente tratados na disciplina de
Cálculo Numérico.
Pode-se utilizar o laço while para obter séries por meio de computador, usado
como a condição de parada um valor limite para suas parcelas, a partir da qual não
se justifica somá-las. Denominando este valor limite de PRECISAO, segue o
algoritmo:

S = 0
calcular u inicial // é o valor de u0
while( |u| > PRECISAO ){
S = S + u
calcular u // é o valor do termo geral ui
}
imprimir S

Os comandos "calcular u inicial" e "calcular u" vão depender de cada série, em


geral é necessário criar variáveis auxiliares para calcular os sucessivos valores de u.
No início, o valor da série é nulo, S = 0. Antes de entra no laço é necessário
calcular a primeira parcela da série pois ele é utilizado como condição do laço while.
Se o valor da primeira parcela for menor do que o limite imposto |u| < PRECISAO o
bloco do while não será executado. Caso contrário seu bloco será executado.
O valor de u em módulo, ou seja |u|, é utilizado para o cado de valores de u
negativos porém maiores do PRECISAO em módulo.
O bloco do while tem dois comandos. O primeiro adiciona o valor de u ao valor
de S. O segundo calcula os sucessivos valores de u. Ao encerrar o bloco, o while
testa novamente a condição. Se a condição for VERDADE entra no laço, recalcula S
e u. Se a condição for FALSE encerra o laço. Imprime o valor da série.

1
Exemplo 7.3 Programa C para calcular S=∑ 2i
, para x = 0.5.
i=0 x
#include <stdio.h>
#define PRECISAO 1.0E-6
int main( void ){
int i;
float x, u, S;
Programação Básica com Linguagem C 223

i = 0 ;
x = 0.5;
u = 1.0;
S = 0.0;

while( fabs(u) > PRECISAO ){


S = S + u;
i = i + 1;
u = pow( x, 2*i );
}
printf("\n S = %f ", S );
return 0;
}
O valor de PRECISAO foi definido como constante e igual a 1.0E-6 (0.000001).
Neste programa foram criadas as variáveis auxiliares i e x para calcular os valores
de u.
O valor inicial de u (u0) é obtido teoricamente.
A variável inteira i é o contador para os termos ou parcelas da série. Seu valor
inicial é 0 (zero).
A variável float x faz parte do termo geral da série. Seu valor é fixo e igual a 0.5.
A variável float u é o termo geral da série. Seu valor inicial e igual a 1.0 (obtido da
teoria matemática).
Os sucessivos valores de u são calculados por dois comandos, incremento de i e
elevar x a 2i, o termo geral da série, dada pela teoria matemática.
Vale destacar que o valor de PRECISAO depende de cada série. Para os propósitos
deste curso, PRECISAO = 1.0E-6 é adequado.
Como a série tem apenas termos positivos, e apenas por este motivo, o comando
while( fabs(u) > PRECISAO ) pode ser substituído por while( u > PRECISAO ).

2 i+1

i x
Exemplo 7.4 Programa C para calcular S=∑ (−1) , para x = 0.7.
i=0 2 i+ 1
#include <stdio.h>
#define PRECISAO 1.0E-6
int main( void ){
int i;
float x, u, S;
i = 0 ;
x = 0.7;
u = x ;
Programação Básica com Linguagem C 224

S = 0.0;
while( fabs(u) > PRECISAO ){
S = S + u;
i = i + 1;
u = pow(-1.0, i)* pow(x, 2*i+1) / (2*i + 1);
}
printf("\n S = %f ", S );
return 0;
}

7.4. Exercícios
Faça um programa em C para calcular valores aproximados das séries:


2i
1. S=∑ , para x = 0.5
i=1 x2i
i

x
2. S=∑ , para x = 0.1
i=0 i!
2 i+ 1

x i
3. S=∑ (−1) , para x = 0.75
i=0 (2i +1)!
2i

i x
4. S=∑ (−1) , para x = 0.75
i=0 (2i )!

ix i
5. S=∑ i
, para x = 0.5
i=0 3

xi +1
6. S=∑ , para x = 1.5
i=0 (i +1)2

i
7. S=∑ i! x , para x = 1.5
i=0

7.5. Recorrência em Séries


Uma outra técnica mais precisa para aproximação de funções é o uso de
fórmulas de recorrência para calcular a soma de séries. Uma fórmula de recorrência
é uma relação entre os termos sucessivos de uma série numérica. Dessa forma,
usando uma fórmula de recorrência, é possível obter o próximo termo da série
usando o valor de termos anteriores. Um exemplo clássico é a sequência de

Fibonacci definida pela fórmula de recorrência F (i)= i , i≤1


{
F i−1+ Fi−2 , i> 1
, note que o

termo Fi é obtido a partir dos dois termos anteriores Fi−1 e Fi−2.


Esta técnica está descrita nos exemplos abaixo.
Programação Básica com Linguagem C 225

Exemplo 7.5 Padrões em série.


9
Seja a série S=1+ x+ x + x + x +⋯+ x =∑ xi .
2 3 4 9

i=0
i ui ui ui
0 u0 1 1
1 u1 x u0x = x
2 u2 x2 u1x = x2
3 u3 x3 u2x = x3
4 u4 x4 u3x = x4
... ... ... ...
i uI xi ui = ui-1x
... ... ... ...
9 u9 x9 u8x = x9
Pode-se gerar esta série a partir do seu termo geral xi, para i variando de 1 a 9.
Observe que há um padrão que pode ser usado para gerar esta série. O termo u 0 =
1, os demais termos são u1 = x, u2 = x2, u3 = x3, u4 = x4, e assim por diante.
Observe que pode-se escrever u1 = 1x, u2 = xx, u3 = x2x, u4 = x3x, e assim por
diante.
O padrão desta série é: fazendo u0 = 1, o próximo termo é igual ao termo anterior
multiplicado por x, ou seja, ui = ui-1x, para i variando de 1 a 9.
Este padrão não se aplica ao primeiro termo ( u0 ), que é usado como valor inicial.
Em termos de algoritmo, usando este padrão, pode-se escrever:
leia x
u = 1
S = 1
para i = 1 até i < 10 faça
u = u*x
S = S + u
fim para
escreva S
Em termos de algoritmo, sem usar este padrão, pode-se escrever:
leia x
S = 1
para i = 1 até i < 10 faça
u = xi
S = S + u
fim para
escreva Soma
O primeiro algoritmo calcula u por meio de multiplicação, já o segundo utiliza
potência. Por isso o primeiro algoritmo, em geral, é mais eficiente do que o
segundo.

A exemplo abaixo apresenta uma recorrência para resolver séries que requerem
fatorial.
Programação Básica com Linguagem C 226

Exemplo 7.6 Padrões em série.


9 i
x 3 x5 x 7 x 9 x 11 x 19 (−1) 2 i+1
Seja a série S= x− + − + − +⋯− =∑ x .
3 ! 5 ! 7 ! 9 ! 11 ! 19 ! i=0 (2i +1)!
i ui ui ui
0 u0 x x
1 u1 -x3/(2ˣ3) -u0x2/(2ˣ3) = -x3/2/3
2 u2 x5/(2ˣ3ˣ4ˣ5) -u1x2/(4ˣ5) = x5/2/3/4/5
3 u3 -x7/(2ˣ3ˣ4ˣ5ˣ6ˣ7) -u2x2/(6ˣ7) = -x7/2/3/4/5/6/7
4 u4 x9/(2ˣ3ˣ4ˣ5ˣ6ˣ7ˣ8ˣ9) -u2x2/(8ˣ9) = x5/2/3/4/5/6/7/8/9
5 u5 -x11/(2ˣ3ˣ4ˣ5ˣ6ˣ7ˣ8ˣ9ˣ10ˣ11) -u2x2/(10ˣ11) = x5/2/3/4/5/6/7/8/9/10/11
... ... ... ...
i uI xi ui = -ui-1x2/[(2ˣi+1)ˣ(2ˣi+2)]
Pode-se gerar esta série a partir do seu termo geral -ui-1x2/[(2ˣi+1)ˣ(2ˣi+2)], para i
variando de 1 a 9, sendo o termo u0 = x.
O padrão desta série é: fazendo u 0 = x, o próximo termo é igual ao termo anterior
multiplicado por -x2/[(2ˣi+1)ˣ(2ˣi+2)], ou seja, ui = -ui-1 ˣ x2/[(2ˣi+1)ˣ(2ˣi+2)], para i
variando de 1 a 9.
Este padrão não se aplica ao primeiro termo ( u0 ), que é usado como valor inicial.
Em termos de algoritmo, usando este padrão, pode-se escrever:
leia x
S = x
u = x
para i = 1 até i < 10 faça
u = -u*x*x/((2*i+1)*(2*i+2))
S = S + u
fim para
escreva S

Nem todas as séries possuem padrões tão evidentes. Os matemáticos e


cientistas da computação tem identificado os padrões das séries de interesse nas
engenharias. A Matemática Discreta trata deste assunto dentre outros.

Vale destacar que x5/(2ˣ3ˣ4ˣ5) = x5/2/3/4/5 porém a divisão exige mais


do computador do que a multiplicação. A expressão do lado direito é
mais adequada para programas de computador. E também mais
elegante em termos de estética matemática.

7.6. Exercícios
Encontre a fórmula de recorrência das séries abaixo e proponha algoritmos para
obter seus valores aproximados:


1
1. S=∑
i=0 i!
i

i
2. S=∑
i=0 i !
Programação Básica com Linguagem C 227


2i
3. S=∑ 2i
, para x = 0.5
i=0 x
∞ i
x
4. S=∑ , para x = 0.1
i=0 i!
∞ 2 i+1
i x
5. S=∑ (−1) , para x = 0.75
i=0 (2 i+ 1)!

x2 i
6. S=∑ (−1)i , para x = 0.75
i=0 (2 i) !

ixi
7. S=∑ i
, para x = 0.5
i=0 3
∞ i+ 1
x
8. S=∑ , para x = 1.5
i=0 (i+1)2

i
9. S=∑ i ! x , para x = 1.5
i=0

7.7. Processamento de Texto


7.8. Cálculo Numérico Elementar
Programação Básica com Linguagem C 228

8. Preprocessamento

A compilação de Programas C começa com o pré-processamento, que trata das


linhas do programa que começam com "#".
O pré-processamento é feito por um módulo do compilador conhecido como
preprocessador.
Serão considerados apenas as diretivas #define e #include.
A diretiva define cria uma abreviatura - conhecida como macro - para um trecho
de código, como MAX abaixo:

#define MAX 1000

A partir deste ponto do programa, MAX é a abreviatura de 1000.


A tarefa de preprocessador é substituir abreviaturas pelos seus valores no
programa-fonte.
A diretiva include acrescenta o conteúdo de um arquivo especificado ao
programa-fonte. É comum os cabeçalhos da Biblioteca Padrão como, por exemplo:

#include <stdio.h>

A tarefa de preprocessador é incluir estes arquivos no programa-fonte.


O resultado do pré-processamento é um novo programa-fonte sem qualquer
#define ou #include ou outra macro. A linha de comando

$ gcc -E programa.c > programa2.c (Linux)


> gcc -E programa.c > programa2.c (Windows)

A opção -E do compilador gcc faz o preprocessamento do programa.c e grava a


versão preprocessada no arquivo programa2.c.
Programação Básica com Linguagem C 229

9. Ambiente de Desenvolvimento Integrado (IDE)

Para compilar e executar programas C recomenda-se o uso de uma IDE -


Integrated Development Environment ou Ambiente de Desenvolvimento Integrado.
Uma IDE é um software que combina recursos, como editor de código-fonte; o
compilador de código-fonte em linguagem de máquina – o código binário; o linker
que gera o programa executável a partir do código binário e da biblioteca padrão.
A IDE Dev-Cpp é uma das mais utilizadas para compilar programas para o
sistema operacional Microsoft Windows, Figura 9.1. Os recursos a serem utilizados
são do Menu Arquivo (Novo, Abrir, Salvar Como e Salvar) e do Executar (Compilar,
Executar, Compilar & Executar e Recompilar Tudo).

Figura 9.1 IDE Dev-Cpp versão 5.11 com o GNU GCC 4.9.2 32-bit.

Para criar um arquivo-fonte basta clicar em Arquivo→Novo→Arquivo Fonte ou


pressionar as duas teclas Ctrl+N. Pode-se usar o primeiro botão da barra de menu
para isso.
Tem duas opções salvar um arquivo aberto: Salvar e Salvar Como. Este último
permite renomear o arquivo.
O menu Executar, possui as opções descritas na Tabela 9.1.

Tabela 9.1 Comandos para compilar, recompilar e executar códigos-fonte C usando


Programação Básica com Linguagem C 230

a IDE Dev-Cpp
Comando Atalho Descrição
Executar→Compilar F9 compila o arquivo-fonte em foco e, se não houver erros, gera o
executável
Executar→Executar F10 executa o programa previamente compilado
Executar→Compilar & F11 compila o arquivo-fonte em foco e, se não houver erros, gera o
Executar executável e o executa
Executar→Recompilar F12 compila novamente todos os arquivo-fonte abertos e, se não
Tudo houver erros, gera o executável
Pode-se ver o resultado do processo de compilação na parte de baixo da IDE,
como pode ser visto na Figura 9.1.
No caso de haver erro no programa-fonte, este é indicado no texto e descrito na
parte de baixo da IDE. Na Figura 9.2 pode-se observar um erro na linha 9 e sua
descrição. Veja que não é tão simples, o erro refere-se à falta de ponto e vírgula
deve ser corrigido na linha 7.

Figura 9.2 Indicação de erro de programação pela IDE Dev-Cpp.

Os compiladores são programados para dar mensagens de aviso (warning em


inglês) quando há suspeita de mal uso da linguagem, mas o programa segue e é
compilado. As mensagens de erro (error em inglês) indicam mal uso da linguagem,
neste caso o programa não é compilado.
Quando o programa é executado, aparece a janela de fundo de cor preta, Figura
9.3. É necessário fechar esta janela para recompilar o programa.

Figura 9.3 Janela de saída do executável gerado pela IDE DevCpp.


Programação Básica com Linguagem C 231

Exemplo 9.1 Digite o programa abaixo na IDE Dev-Cpp e salve-o como


Exemplo31.c, em seguida compile-o, corrija os erros se houver e execute-o.
#include <stdio.h>
int main( void ){
printf("Olá mundo");
return 0;
}
Vale destacar alguns problemas que podem ocorrer. Erro devido ao nome do
arquivo: nome de arquivos podem ter letras e números porém do alfabeto inglês e
não deve conter espaços. Exemplos de nomes adequados: Programa02.c,
MeuPrograma.c, Exemplo-31.c.
Pode ocorrer erros devido ao nome inadequado da pasta onde foi salvo o arquivo.
Erros de digitação são extremamente comuns e requer a paciência de quem
programa para corrigi-los.
Nos primeiros programas digitados e compilados por quem programa é muito
comum ter que compilar e recompilar o mesmo programa várias vezes para
corrigir erros.
Quem programa deve ter paciência para superar esta fase inicial. Quanto mais
atenção aos detalhes mais rapidamente aprende-se a programar sem erros.
Ninguém gosta de corrigir erros de programa de computador mas eles são
inevitáveis, nós seres humanos pensamos em alto nível e a máquina é de baixo
nível, funciona passo a passo, detalhe a detalhe.
Os compiladores são extremamente exigentes.

Exemplo 9.2 Digite o programa abaixo na IDE Dev-Cpp e salve-o como


SaindoDados.c, em seguida compile-o, corrija os erros se houver e execute-o.
#include <stdio.h>
int main( void ){
printf( "Meu nome é: … " );
return 0;
}

Exemplo 9.3 Digite o programa abaixo na IDE Dev-Cpp e salve-o como ESDados.c,
em seguida compile-o, corrija os erros se houver e execute-o.
#include <stdio.h>

int main( void ){


int idade;
printf( "Digite sua idade em anos:" );
scanf( "%d", &idade );
Programação Básica com Linguagem C 232

printf( "Minha idade é %d anos", idade );


return 0;
}
Observe a organização do código-fonte, os comandos foram digitados alinhados
com a palavra main. Isto se chama edentação e ajuda na legibilidade do programa.
Uma boa prática de programação é a edentação, acostume-se a usá-la.

Exemplo 9.4 Digite o programa abaixo na IDE Dev-Cpp e salve-o como Soma.c, em
seguida compile-o, corrija os erros se houver e execute-o.
#include <stdio.h>
int main( void ){
int a, b, soma;
a = 3;
b = 4;
soma = a + b;
printf( "A soma é %d", soma );
return 0;
}

No Linux pode-se utilizar o Code::Blocks de www.codeblocks.org.

No Android pode-se usar o CppDroid C/C++ IDE, disponível na Play


Store.

Faça o download do Dev-Cpp de http://orwelldevcpp.blogspot.com.br,


Escolha a opção que inclui o TDM-GCC 4.9.2 e instale-o no seu
computador.

9.1.1. Editoração, Compilação e Debug

9.1.2. Projetos de Sistemas


Programação Básica com Linguagem C 233

10. Uso do Terminal

No Linux, o caractere $ indica o prompt que costuma aparecer no terminal


Com o gcc instalado no seu sistema, para compilar um Programa C dê o
camando no terminal Linix:

$ gcc programa.c -o programa

Em que:

• programa.c nome do arquivo-fonte


• -o gerar o programa executável
• programa nome do programa executável

Para executar o programa executável de o seguinte comando no terminal:

$./programa

Em que os caracteres ./ indicam que o programa está no diretório (pasta) atual.

No Windows, o caractere > indica o prompt que costuma aparecer no terminal.

Pesquise na wikipédia: compilando pelo terminal

Pesquise na web: compilando pelo terminal


Programação Básica com Linguagem C 234

11. Makefile

Uma boa prática para desenvolver programas grandes e complexos é dividi-los


em vários arquivos, cada arquivo tratando de um aspecto do problema. Uma
desvantagem desta técnica é a compilação dos arquivos individuais, principalmente
quando há interdependência entre os arquivos e opções adicionais, como uso de
bibliotecas.
Existe um utilitário muito usado, o GNU make, que facilita esse tipo de tarefa,
que permite o gerenciamento dos arquivos a serem compilados em um arquivo
chamado Makefile.
O Makefile ajuda no desenvolvimento de projetos de softwares, sem o uso de
IDE. Ele contem um conjunto de diretivas usadas pela ferramenta de automação de
compilação make para gerar um programa executável.
O utilitário make determina automaticamente quais partes de um grande
programa ou projeto precisam ser recompilado e emite comandos para recompilá-
los - GNU make (https://www.gnu.org/software/make/manual/) Version 4.3, 2020.
Programação Básica com Linguagem C 235

12. Sintaxe C em Backus-Naur Form

A Backus-Naur Form é uma sequência de expressões regulares, usa alguns


operadores de repetição como * para 0 ou mais itens e + para 1 ou mais itens;
expressões entre [] são opcionais.
<translation-unit> ::= {<external-declaration>}*

<external-declaration> ::= <function-definition>


| <declaration>

<function-definition> ::= {<declaration-specifier>}* <declarator> {<declaration>}* <compound-statement>

<declaration-specifier> ::= <storage-class-specifier>


| <type-specifier>
| <type-qualifier>

<storage-class-specifier> ::= auto


| register
| static
| extern
| typedef

<type-specifier> ::= void


| char
| short
| int
| long
| float
| double
| signed
| unsigned
| <struct-or-union-specifier>
| <enum-specifier>
| <typedef-name>

<struct-or-union-specifier> ::= <struct-or-union> <identifier> { {<struct-declaration>}+ }


| <struct-or-union> { {<struct-declaration>}+ }
| <struct-or-union> <identifier>

<struct-or-union> ::= struct


| union

<struct-declaration> ::= {<specifier-qualifier>}* <struct-declarator-list>

<specifier-qualifier> ::= <type-specifier>


| <type-qualifier>

<struct-declarator-list> ::= <struct-declarator>


| <struct-declarator-list> , <struct-declarator>

<struct-declarator> ::= <declarator>


| <declarator> : <constant-expression>
| : <constant-expression>

<declarator> ::= {<pointer>}? <direct-declarator>

<pointer> ::= * {<type-qualifier>}* {<pointer>}?

<type-qualifier> ::= const


| volatile
Programação Básica com Linguagem C 236

<direct-declarator> ::= <identifier>


| ( <declarator> )
| <direct-declarator> [ {<constant-expression>}? ]
| <direct-declarator> ( <parameter-type-list> )
| <direct-declarator> ( {<identifier>}* )

<constant-expression> ::= <conditional-expression>

<conditional-expression> ::= <logical-or-expression>


| <logical-or-expression> ? <expression> : <conditional-expression>

<logical-or-expression> ::= <logical-and-expression>


| <logical-or-expression> || <logical-and-expression>

<logical-and-expression> ::= <inclusive-or-expression>


| <logical-and-expression> && <inclusive-or-expression>

<inclusive-or-expression> ::= <exclusive-or-expression>


| <inclusive-or-expression> | <exclusive-or-expression>

<exclusive-or-expression> ::= <and-expression>


| <exclusive-or-expression> ^ <and-expression>

<and-expression> ::= <equality-expression>


| <and-expression> & <equality-expression>

<equality-expression> ::= <relational-expression>


| <equality-expression> == <relational-expression>
| <equality-expression> != <relational-expression>

<relational-expression> ::= <shift-expression>


| <relational-expression> < <shift-expression>
| <relational-expression> > <shift-expression>
| <relational-expression> <= <shift-expression>
| <relational-expression> >= <shift-expression>

<shift-expression> ::= <additive-expression>


| <shift-expression> << <additive-expression>
| <shift-expression> >> <additive-expression>

<additive-expression> ::= <multiplicative-expression>


| <additive-expression> + <multiplicative-expression>
| <additive-expression> - <multiplicative-expression>

<multiplicative-expression> ::= <cast-expression>


| <multiplicative-expression> * <cast-expression>
| <multiplicative-expression> / <cast-expression>
| <multiplicative-expression> % <cast-expression>

<cast-expression> ::= <unary-expression>


| ( <type-name> ) <cast-expression>

<unary-expression> ::= <postfix-expression>


| ++ <unary-expression>
| -- <unary-expression>
| <unary-operator> <cast-expression>
| sizeof <unary-expression>
| sizeof <type-name>

<postfix-expression> ::= <primary-expression>


| <postfix-expression> [ <expression> ]
| <postfix-expression> ( {<assignment-expression>}* )
| <postfix-expression> . <identifier>
| <postfix-expression> -> <identifier>
| <postfix-expression> ++
| <postfix-expression> --

<primary-expression> ::= <identifier>


| <constant>
| <string>
| ( <expression> )

<constant> ::= <integer-constant>


| <character-constant>
| <floating-constant>
| <enumeration-constant>

<expression> ::= <assignment-expression>


| <expression> , <assignment-expression>

<assignment-expression> ::= <conditional-expression>


| <unary-expression> <assignment-operator> <assignment-expression>

<assignment-operator> ::= =
| *=
| /=
| %=
| +=
Programação Básica com Linguagem C 237

| -=
| <<=
| >>=
| &=
| ^=
| |=

<unary-operator> ::= &


| *
| +
| -
| ~
| !

<type-name> ::= {<specifier-qualifier>}+ {<abstract-declarator>}?

<parameter-type-list> ::= <parameter-list>


| <parameter-list> , ...

<parameter-list> ::= <parameter-declaration>


| <parameter-list> , <parameter-declaration>

<parameter-declaration> ::= {<declaration-specifier>}+ <declarator>


| {<declaration-specifier>}+ <abstract-declarator>
| {<declaration-specifier>}+

<abstract-declarator> ::= <pointer>


| <pointer> <direct-abstract-declarator>
| <direct-abstract-declarator>

<direct-abstract-declarator> ::= ( <abstract-declarator> )


| {<direct-abstract-declarator>}? [ {<constant-expression>}? ]
| {<direct-abstract-declarator>}? ( {<parameter-type-list>}? )

<enum-specifier> ::= enum <identifier> { <enumerator-list> }


| enum { <enumerator-list> }
| enum <identifier>

<enumerator-list> ::= <enumerator>


| <enumerator-list> , <enumerator>

<enumerator> ::= <identifier>


| <identifier> = <constant-expression>

<typedef-name> ::= <identifier>

<declaration> ::= {<declaration-specifier>}+ {<init-declarator>}* ;

<init-declarator> ::= <declarator>


| <declarator> = <initializer>

<initializer> ::= <assignment-expression>


| { <initializer-list> }
| { <initializer-list> , }

<initializer-list> ::= <initializer>


| <initializer-list> , <initializer>

<compound-statement> ::= { {<declaration>}* {<statement>}* }

<statement> ::= <labeled-statement>


| <expression-statement>
| <compound-statement>
| <selection-statement>
| <iteration-statement>
| <jump-statement>

<labeled-statement> ::= <identifier> : <statement>


| case <constant-expression> : <statement>
| default : <statement>

<expression-statement> ::= {<expression>}? ;

<selection-statement> ::= if ( <expression> ) <statement>


| if ( <expression> ) <statement> else <statement>
| switch ( <expression> ) <statement>

<iteration-statement> ::= while ( <expression> ) <statement>


| do <statement> while ( <expression> ) ;
| for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>

<jump-statement> ::= goto <identifier> ;


| continue ;
| break ;
| return {<expression>}? ;

This grammar was adapted from Section A13 of The C programming language, 2nd edition, by Brian W. Kernighan and Dennis M.
Ritchie,Prentice Hall, 1988.
Programação Básica com Linguagem C 238

Fonte: https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%20C%20in%20Backus-Naur%20form.htm
Programação Básica com Linguagem C 239

13. Buscando Padrões para fins de Algoritmo

Os conceitos abaixo buscam definir os termos mas não orienta como construir
algoritmos ou mesmo programa de computador.
Algoritmo é uma sequência finita de instruções.
Programa de computador é um conjunto de instruções que descrevem uma
tarefa a ser realizada por um computador.
Dada uma tarefa, como construir a sequência de instruções capaz de resolvê-la
por computador?
A resposta é: analisar a tarefa e buscar um padrão e, a partir dele, identificar a
sequência de instruções capaz de resolvê-la por computador.

Exemplo 13.1 Pode-se criar um algoritmo para subir escadas?


Para responder esta pergunta é necessário responder se há um padrão em subir
escada.
Escadas são constituídas de degraus, que são a escada propriamente dita, o
resultado de subir escadas é deslocar-se através destes degraus passo a passo,
um de cada vez, desde um ponto de partida até um ponto de chegada.
Vamos considerar uma solução para humanos, logo é necessário se posicionar no
início da escada. Em seguida subir o primeiro degrau. Se a escada tiver um único
degrau então chegou ao seu final. Caso contrário deve-se subir mais um degrau.
Se a escada tiver dois degraus então chegou ao seu final. E assim sucessivamente.
Generalizando:

1. posicionar no início da escada


2. subir um degrau
3. verificar se é o fim da escada
4. se não for o fim da escada, executar as tarefas 2, 3 e 4 nesta ordem
5. encerrar

Verifique que foi necessário definir escada como um conjunto de degraus, que
possui início e fim. Também foi necessário estabelecer a ação de subir um degrau.
Por fim, foi criado um método para identificar o fim da escada.
Embora estas "coisas" não estejam na pergunta, elas tiveram que ser criadas: são
Programação Básica com Linguagem C 240

meios para se atingir o fim proposto.


É de suma importância identificar e criar os meios necessários para se elaborar
algoritmos. Estes meios são identificados a partir do problema proposto.

O que é um padrão para fins de algoritmo?

Um padrão para fins de algoritmo é uma sequência que se repete, onde


um conjunto de coisas permanece fixa durante o processo e um outro
conjunto de coisas muda neste mesmo processo.

No exemplo acima, as coisas são a escada, seus degraus, as posições


inicial e final da escada, e a posição da pessoa que sobe a escada. O
processo é o ato humano de subir uma escada.

As coisas que são permanecem fixas são a escada, a sua quantidade de


degraus, suas posições inicial e final.
A coisa que varia é a posição da pessoa na escada.

O algoritmo consiste em, utilizando os recursos – as coisas que não


mudam, variar a posição da pessoa – fazê-la subir a escada do início até
o fim, subindo a escada sequencialmente, degrau a degrau desde o
início e verificando quando se deve subir o próximo degrau ou encerrar.

Para decidir entre mais um degrau ou encerrar é feita a pergunta:


chegou no fim da escada? Se a resposta for FALSA a opção é subir mais
um degrau. Se a resposta for VERDADEIRA a opção é encerrar pois
chegou ao final da escada – o último degrau.

Exemplo 13.2 Pode-se criar um algoritmo contar todos os números existentes?


Para responder esta pergunta é necessário responder se há um padrão de
contagem.
No caso de números, é possível contá-los por meio de algoritmos. O problema que
foi colocado torna impossível definir o início e o fim do conjunto de números, pois
requer contar todos, o conjunto dos números tem elementos em número ilimitado,
infinito.
Logo, um algoritmo para contar todos os números existentes não pode ser criado.
O computador entra em loop quando executa uma tarefa sem fim.

Exemplo 13.3 Pode-se criar um algoritmo para contar todos os números inteiros
compreendidos entre 10 e 20?
Sim, uma possibilidade é o algoritmo:

1. Iniciar o contador com 0 (elemento neutro da operação adição)


2. Iniciar com 11
Programação Básica com Linguagem C 241

3. Se for maior ou igual a 20 então encerrar


4. Contar o número
5. Ir para o próximo número inteiro
6. Voltar ao passo 3

Note que a solução deste problema é estranha para o pensamento humano: Como
eu começo com 11 e testo se é menor do que 20 logo em seguida? Não é
esquisito?
Observe que os passos 3 a 6 formam um bloco que se repete várias vezes. Os
itens 1 e 2 são executados uma única vez. Ao executar o bloco 3-6 pela segunda
vez, pela terceira vez e assim por diante, é que fica claro o algoritmo.
Este é o padrão para qualquer contagem de inteiros que tenha início e fim bem
definidos.
Note a diferença entre solução para seres humanos e para máquinas: máquinas
funcionam a partir de rotinas repetitivas, seres humanos não.
Verifique que pode existir mais de um algoritmo para resolver um problema, o
melhor dentre eles é chamado algoritmo otimizado.
Normalmente, começa-se com um algoritmo que resolve o problema e vai
melhorando-o até que ele fique otimizado.
Vale a Regra de Ouro: o que conta é o resultado.
Não confunda a Regra de Ouro com a vida em sociedade, pois a relação entre
seres humanos envolve ética e moral, onde resultados requer o uso de meios
aceitos pelo grupo.

Exemplo 13.4 Pode-se criar um algoritmo para somar todos os números inteiros
compreendidos entre a e b?
Sim, uma possibilidade é o algoritmo:

1. Iniciar a soma com 0


2. Iniciar com o número inteiro a
3. Se for maior ou igual a b então encerrar
4. Somar o número
5. Ir para o próximo número inteiro
6. Voltar ao passo 3

Veja que foi generalizado o padrão do exemplo anterior, para qualquer intervalo
inteiro (a,b).

Exemplo 13.5 Pode-se criar um algoritmo para contar todos os números reais
compreendidos entre 10 e 20?
No problema colocado, embora seja possível definir o início e o fim do conjunto de
números reais, existem infinitos números reais entre 10 e 20. Desta forma não tem
como definir o número de repetições para o padrão de contagem. O algoritmo não
Programação Básica com Linguagem C 242

teria fim.
Não, não há algoritmo para contar todos os números reais por computador no
intervalo indicado (ou para qualquer outro intervalo finito).
Pode-se afirmar, por outro lado, que há algoritmo para contagem aproximada de
números reais por computador de dado intervalo finito.

Exemplo 13.6 Pode-se criar um algoritmo para fazer o produto de todos os


números inteiros compreendidos entre a e b?
Sim, uma possibilidade é o algoritmo:

1. Iniciar o produto com 1 (elemento neutro da operação de multiplicação)


2. Iniciar com o número inteiro a
3. Se for maior ou igual a b então encerrar
4. Fazer o produto do número
5. Ir para o próximo número inteiro
6. Voltar ao passo 3

Como pode-se observar nos exemplos anteriores, estes algoritmos possuem


valores iniciais, inicio e fim bem definidos e um bloco que se repete um número
finito de vezes, e que se encerra ao atender uma condição de parada.
De modo geral, tarefas que podem ser resolvidas por computador possuem
padrões que envolvem repetição, que podem ser reutilizável e que podem ser
generalizados. Normalmente, estas tarefas possuem padrões matemáticos.
Uma observação importante, para ajudar a construir algoritmos, é que uma
tarefa grande devem ser subdividida em tarefas menores, a assim por diante. Esta
regra é denominada "dividir para resolver".
Transformar algoritmo em programa de computador envolver usar as regras
sintáticas e semânticas da linguagem de programação. As linguagens de
programação podem ser usadas para expressar algoritmos com precisão.

Algoritmo não são programas de computador. A partir de algoritmos


pode-se fazer programas de computador. Pode-se dizer que programas
de computador são algoritmos mais elaborados e muito mais
detalhados.

Os algoritmos estão mais próximos da capacidade de representação


humana. Os programas de computador estão mais próximos da
capacidade operacional das máquinas.

Pode-se propor a sequência: problemas formulados por seres humano


são elaborados na forma de algoritmos que, por sua vez, são
transformados em programas de computador.
Programação Básica com Linguagem C 243

13.1. Soma: Humanos x Computador


Como nós, seres humanos, somamos números?
Para analisar o processo de soma feita por humanos, considere a soma dos
números: 3, 5, 2, 9 e 4.
A maioria de nós, primeiramente soma 3 com 5 que é igual a 8. Em seguida, 8
com 2 que é 10. Depois 10 com 9 que dá 19 e, por fim, 19 com 4 dando o total de
23.
Onde são guardados os valores 8,10,19 e 23? Seres humanos fazem o uso de
memórias biológicas, temos muita memória. Estes valores são guardados na
memória.
Observe que, em geral, somamos os números dois a dois. Não somamos todos
de uma vez, deve ter alguém capaz disso mas são exceções e não a regra.
O Computador, para efetuar a soma indicada também faz uso de memória, ele
usa de sua que é do tipo eletrônica. Computadores modernos têm vários bancos de
memória à sua disposição.
Os Computadores precisam reservar memória para realizar seus processos e,
para isso ele seleciona uma região de sua memória e dá-lhe um nome para que ela
possa ser referenciada durante processamento.
Seja S o nome da região da memória de um Computador selecionada para ser
utilizada no processo de soma. Inicialmente o Computador atribui a S o valor zero
(elemento neutro da soma). Ele então começa a soma. Ele soma S com 3, logo S
agora é igual a 3. Em seguida, soma S com 5, assim S muda seu valor para 8.
Depois soma S com 2, S agora é 10. Ainda soma S com 9, ficando S igual a 19 e, por
fim, S é somando com 4, com S igual a 23. S, ao final, tem o valor da soma é igual a
23.
Observe que o Computador soma os números dois a dois, porém um dos
números é sempre sua memória de trabalho. Ele reserva a memória S. Faz S igual a
zero. Soma cada número a S, um a uma, do começo ao fim.
Pode-se afirma que, de modo geral, seres Humanos e Computadores somam de
modo similar. Nós, seres humanos, possuímos um algoritmo nem sempre explícito.
Já os Computadores requerem um detalhamento muito maior e de modo explícito,
passo a passo.
Nas máquinas, sua memória pode ser organizada de várias formas, seus valores
são alterados continuamente. A memória é entendida como algo variável.
A reserva de memória nas máquinas é chamando de declaração de variáveis, é
preciso dar um nome para a região da memória, este nome é denominado variável.
A memória das máquinas podem receber vários tipos de valores como texto,
números inteiros e números fracionários. Por uma questão de organização, as
variáveis são declaradas com tipos bem definidos, permitindo as operações
específicas para aquele tipo.

13.2. Sim e Não: Humanos x Computador


Como nós, seres humanos, diferenciamos algo falso de algo verdadeiro?
Nós, seres humanos, somos capazes de lidar com as diferenças melhor do que
Programação Básica com Linguagem C 244

as máquinas. Entre o preto e o branco, somos capazes de identificar várias nuances


de cores cinzas.
O Computador não é versátil como os seres humanos. Ele reconhece apenas
dois estados lógicos: verdadeiro ou falso, sim ou não, ligado ou desligado, alto ou
baixo, preto ou branco e assim por diante. Ele é binário e nós devemos transformar
nossas ideias em conformidade com estas duas possibilidades quando necessário.

13.3. Comparação: Humanos x Computador


Como nós, seres humanos, comparamos duas ou mais coisas?
Nós, seres humanos, somos capazes de lidar com vários tipos de comparações.
O computador está restrito às de cunho matemáticos, como maior, menor, igual; e
também as lógicas, como falso ou verdadeiro.

13.4. Humanos x Computador


Os Computadores são máquinas projetadas e construídas por seres humanos,
eles são capazes de processar algoritmos, que são tarefas precisamente definidas,
com velocidade e exatidão. Eles estão aptos para resolver situações previstas pelo
programa, foras destes casos são ineficazes.
A mente humana, em geral, não é rápida como as máquinas, mas temos bom
senso, criatividade e emoções. Somos capazes de lidar com situações inimagináveis
ou imprevisíveis, temos consciência de nós mesmos e do mundo. Vivemos,
convivemos e interagimos.
Muitos especialistas entendem que estamos numa época de transição, a nova
era que anuncia é da inteligência artificial. Quando então o Computador causará
grandes impactos e transformações tecnológicas, com reflexos na sociedade e seus
modos de produção, desenvolvimento, ciência, tecnologia e transformação do
mundo.

13.5. Notas Adicionais sobre a Linguagem C


Um programa escrito em C é traduzido para a linguagem de máquina por um
compilador. Para que o compilador consiga traduzir o código fonte para o código de
máquina (muito baixo nível), é necessário que cada instrução seja escrita de acordo
com regras preestabelecidas. Estas regras são chamadas sintaxe da instrução e
quando não são obedecidas diz-se que existe erro de sintaxe.
Se o código fonte contêm algum erro de sintaxe, o compilador não o traduz para
a linguagem de máquina e indica qual o tipo de erro cometido e a instrução onde
este erro aconteceu.
Naturalmente, cada instrução tem uma finalidade específica. Ou seja, a
execução de uma instrução resulta na realização de uma ação correspondente, a
execução sequencial das instruções do programa resulta na tarefa para a qual o
programa foi escrito. A ação resultante da execução de uma instrução e chamada
semântica da instrução.
Infelizmente, um programa pode não conter erros de sintaxe (e, portanto, pode
ser executado), mas a sua execução pode não fornecer como saída o resultado
Programação Básica com Linguagem C 245

esperado para alguma entrada. Neste caso, dizemos que o programa contem erros
de lógica que, ao contrário dos erros de sintaxe, que são detectados pelo
compilador, são por vezes de difícil detecção.
Para aprender a programar em C e necessário que se aprenda suas
instruções (para que se conheça o que o processador e capaz de fazer), a sintaxe
de cada um destas instruções e as suas semânticas. Aliado a isto, deve-se ter um
bom desenvolvimento de lógica de programação para que escolha as instruções
necessárias e a sequência segundo a qual estas instruções devem ser escritas,
para que o programa, ao ser executado, execute a tarefa pretendida.
Felizmente ou infelizmente, para cada tarefa que se pretende, não existe apenas
uma sequência de instruções que a realize. Ou seja, dado um problema não existe
apenas um programa que o resolva.
Devemos procurar fazer o melhor programa, entendendo-se como melhor
programa um programa que tenha boa legibilidade, cuja execução demande o
menor tempo possível e que necessite, para sua execução, a utilização mínima da
memória de máquina. O melhor programa depende da experiência, habilidade e
criatividade de quem o produz.

13.6. Dado e Informação

Atualmente, o termo dado é associado com computadores na mente de muitas


pessoas. No entanto, os dados (como em "dado" – fatos ou medidas) têm sido
usados como um termo por cientistas e estudiosos por séculos. Tal como aconteceu
com um livro caixa, um entalhe em um pedaço de madeira, ou um registro
manuscrito, dados armazenados em um computador (ou em suporte digital) é uma
representação de fatos sobre o mundo. Estes fatos podem ser as leituras de
temperatura, endereços de clientes, os pontos em uma imagem, as características
de um som em um dado instante, um filme digital ou uma série de outras coisas.
Como os dados do computador não são fatos, mas sua representação, sua
precisão e utilidade dependem não só da precisão dos dados originais, mas do seu
contexto no computador. No fundo, os dados do computador são compostos de
estados binários (representado numericamente como uns ou zeros) armazenados
usando algumas características físicas, tais como uma carga elétrica ou magnética
ou um local capaz de absorver ou refletir a luz.
Uma sequência de uns e zeros em um computador não tem nenhum significado
inerente. Como, por exemplo, o padrão de bits 01000001 equivale ao número 65 no
sistema decimal e equivale a letra maiúscula "A" no código de caracteres ASCII.
A fim de ser interpretada uma sequência de uns e zeros deve ser atribuída a
uma categoria, tais como inteiro ou ponto flutuante (decimal) ou caracteres. O
programa executável determina a localização e o número de bits a ser transferido
para a memória em conformidade com o tipo e o valor de cada categoria de dado.
Os itens de dados podem ser tratados convenientemente como um lote, ou
diferentes tipos de dados como nomes, endereços e números. Ao criar uma
estrutura dentro do programa para representar os dados, o programador deve estar
ciente de sua finalidade e utilização. A linguagem de programação e instruções de
Programação Básica com Linguagem C 246

código define o contexto de dados dentro das regras da linguagem. No entanto, o


significado dos dados deve finalmente ser construído pelos seres humanos que os
usam. Por exemplo, se uma pontuação de teste é bom, ruim ou indiferente, não é
uma característica dos dados em si, mas é determinada por efeitos das regras do
teste. É por isso que se faz a distinção entre o valor do dado e a informação do
dado. O valor do dado é inerente ao sistema de representação e a sua informação
depende do contexto e do usuário que o interpreta.
Em termos de circuitos de máquina de um computador há apenas um tipo de
dado, uma série de bits (dígitos binários) preenchendo sequencialmente posições
de memória. A interpretação destes bits pelos usuários de computador é totalmente
arbitrária. O objetivo de usar tipos de dados é definir conceitos úteis, tais como
número inteiro, número de ponto flutuante, ou caracteres em termos de como eles
são armazenados na memória do computador e que operações pode-se fazer com
eles.
Programação Básica com Linguagem C 247

14. Anexos

14.1. Tabela ASCII


A Tabela 14.1 contem os caracteres do código ASCII de 0 a 31 e 127, que são
códigos de controle e não são impressos. Já os de 32 a 126 podem ser impressos. O
código 32 corresponde ao carácter espaço.

Tabela 14.1 Caracteres do código ASCII de 0 a 127, com seus valores decimais (D),
binários (B) e seus símbolos (S)
D B S D B S D B S D B S
0 00000000 NUL 32 00100000   64 01000000 @ 96 01100000 `
1 00000001 SOH 33 00100001 ! 65 01000001 A 97 01100001 a
2 00000010 STX 34 00100010 " 66 01000010 B 98 01100010 b
3 00000011 ETX 35 00100011 # 67 01000011 C 99 01100011 c
4 00000100 EOT 36 00100100 $ 68 01000100 D 100 01100100 d
5 00000101 ENQ 37 00100101 % 69 01000101 E 101 01100101 e
6 00000110 ACK 38 00100110 & 70 01000110 F 102 01100110 f
7 00000111 BEL 39 00100111 ' 71 01000111 G 103 01100111 g
8 00001000 BS 40 00101000 ( 72 01001000 H 104 01101000 h
9 00001001 HT 41 00101001 ) 73 01001001 I 105 01101001 i
10 00001010 LF 42 00101010 * 74 01001010 J 106 01101010 j
11 00001011 VT 43 00101011 + 75 01001011 K 107 01101011 k
12 00001100 FF 44 00101100 , 76 01001100 L 108 01101100 l
13 00001101 CR 45 00101101 – 77 01001101 M 109 01101101 m
14 00001110 SO 46 00101110 . 78 01001110 N 110 01101110 n
15 00001111 SI 47 00101111 / 79 01001111 O 111 01101111 o
16 00010000 DLE 48 00110000 0 80 01010000 P 112 01110000 p
17 00010001 DC1 49 00110001 1 81 01010001 Q 113 01110001 q
18 00010010 DC2 50 00110010 2 82 01010010 R 114 01110010 r
19 00010011 DC3 51 00110011 3 83 01010011 S 115 01110011 s
20 00010100 DC4 52 00110100 4 84 01010100 T 116 01110100 t
21 00010101 NAK 53 00110101 5 85 01010101 U 117 01110101 u
22 00010110 SYN 54 00110110 6 86 01010110 V 118 01110110 v
23 00010111 ETB 55 00110111 7 87 01010111 W 119 01110111 w
24 00011000 CAN 56 00111000 8 88 01011000 X 120 01111000 x
Programação Básica com Linguagem C 248

D B S D B S D B S D B S
25 00011001 EM 57 00111001 9 89 01011001 Y 121 01111001 y
26 00011010 SUB 58 00111010 : 90 01011010 Z 122 01111010 z
27 00011011 ESC 59 00111011 ; 91 01011011 [ 123 01111011 {
28 00011100 FS 60 00111100 < 92 01011100 \ 124 01111100 |
29 00011101 GS 61 00111101 = 93 01011101 ] 125 01111101 }
30 00011110 RS 62 00111110 > 94 01011110 ^ 126 01111110 ~
31 00011111 US 63 00111111 ? 95 01011111 _ 127 01111111 DEL

Na Tabela 14.2 estão os demais caracteres códigos ASCII (estendido).

Tabela 14.2 Caracteres do código ASCII de 128 a 255, com seus valores decimais
(D), binários (B) e seus símbolos (S)

D B S D B S D B S D B S
128 10000000 Ç 160 10100000 á 192 11000000 └ 224 11100000 Ó
129 10000001 ü 161 10100001 í 193 11000001 ┴ 225 11100001 ß
130 10000010 é 162 10100010 ó 194 11000010 ┬ 226 11100010 Ô
131 10000011 â 163 10100011 ú 195 11000011 ├ 227 11100011 Ò
132 10000100 ä 164 10100100 ñ 196 11000100 ─ 228 11100100 õ
133 10000101 à 165 10100101 Ñ 197 11000101 ┼ 229 11100101 Õ
134 10000110 å 166 10100110 ª 198 11000110 ã 230 11100110 µ
135 10000111 ç 167 10100111 º 199 11000111 Ã 231 11100111 þ
136 10001000 ê 168 10101000 ¿ 200 11001000 ╚ 232 11101000 Þ
137 10001001 ë 169 10101001 ® 201 11001001 ╔ 233 11101001 Ú
138 10001010 è 170 10101010 ¬ 202 11001010 ╩ 234 11101010 Û
139 10001011 ï 171 10101011 ½ 203 11001011 ╦ 235 11101011 Ù
140 10001100 î 172 10101100 ¼ 204 11001100 ╠ 236 11101100 ý
141 10001101 ì 173 10101101 ¡ 205 11001101 ═ 237 11101101 Ý
142 10001110 Ä 174 10101110 « 206 11001110 ╬ 238 11101110 ¯
143 10001111 Å 175 10101111 » 207 11001111 ¤ 239 11101111 ´
144 10010000 É 176 10110000 ░ 208 11010000 ð 240 11110000 ≡
145 10010001 æ 177 10110001 ▒ 209 11010001 Ð 241 11110001 ±
146 10010010 Æ 178 10110010 ▓ 210 11010010 Ê 242 11110010 ‗
147 10010011 ô 179 10110011 │ 211 11010011 Ë 243 11110011 ¾
148 10010100 ö 180 10110100 ┤ 212 11010100 È 244 11110100 ¶
149 10010101 ò 181 10110101 Á 213 11010101 ı 245 11110101 §
150 10010110 û 182 10110110 Â 214 11010110 Í 246 11110110 ÷
151 10010111 ù 183 10110111 À 215 11010111 Î 247 11110111 ¸
152 10011000 ÿ 184 10111000 © 216 11011000 Ï 248 11111000 °
153 10011001 Ö 185 10111001 ╣ 217 11011001 ┘ 249 11111001 ¨
154 10011010 Ü 186 10111010 ║ 218 11011010 ┌ 250 11111010 ·
155 10011011 ø 187 10111011 ╗ 219 11011011 █ 251 11111011 ¹
156 10011100 £ 188 10111100 ╝ 220 11011100 ▄ 252 11111100 ³
157 10011101 Ø 189 10111101 ¢ 221 11011101 ¦ 253 11111101 ²
158 10011110 × 190 10111110 ¥ 222 11011110 Ì 254 11111110 ■
Programação Básica com Linguagem C 249

D B S D B S D B S D B S
159 10011111 ƒ 191 10111111 ┐ 223 11011111 ▀ 255 11111111 nbsp

14.2. Pseudocódigo
Pseudocódigo é uma forma genérica de escrever algoritmos, nele é utilizado
uma linguagem simples sem necessidade de conhecer a sintaxe de nenhuma
linguagem de programação. Um exemplo de pseudocódigo é o Portugol, que utiliza
o compilador Visualg (https://sourceforge.net/projects/visualg30/).

pseudocódigo - linguagem de programação simplificada e genérica

Algoritmo 14.1 Forma Geral do Pseudocódigo

Algoritmo <nome_do_algoritmo>
<declaração de variáveis>
<subalgoritmos>
Início
<corpo do algoritmo>
Fim.
Para estudar os comandos do Portugol, consulte o Manual do Visualg 3.0,
disponível em http://visualg3.com.br/.

Exemplo 14.1 O exemplo de pseudocódigo para o cálculo da média de um aluno


Algoritmo Média
Var N1, N2, Média : real
Início
Leia N1, N2
Média <– (N1 + N2) / 2
Se Média >= 6.0
Então
Escreva “Aprovado”
Senão
Escreva “Reprovado”
Fim_se
Fim.
Programação Básica com Linguagem C 250

14.3. Fluxograma
Fluxogramas representam gráfica e sequencialmente os comandos que
compõem um algoritmo. Seus principais objetivos:

• padronizar a representação de algoritmos


• facilitar a leitura e o entendimento de programas de computador
• analisar algoritmos

O fluxograma não fornece detalhes e sim apresenta as tarefas sequencialmente,


com uma indicação de início, e as setas indicando o fluxo de controle. As atividades
são representadas graficamente, existem muitos símbolos para representar
fluxogramas. O programador pode também criar seus próprios símbolos. A Figura
14.1 apresenta os principais elementos de um fluxograma, os mais básicos.

Figura 14.1 Elementos básicos para a criação de fluxogramas.

Embora ainda útil, fluxogramas é muitas vezes complementado por outras


técnicas de representação de programas.

Exemplo 14.2 O exemplo de fluxograma para a solução do problema "a partir de


um número inteiro, obtido via teclado, verificar se ele é ímpar ou par e informar o
resultado no vídeo", é mostrado na Figura 14.2.
Programação Básica com Linguagem C 251

Figura 14.2 Fluxograma para exibir se um número inteiro é par ou ímpar.

O software Dia (http://dia–installer.de/), Figura 14.3, é uma ferramenta que


permite criar fluxogramas.

Figura 14.3 Programa Dia, para criação de fluxogramas.

14.4. Formatos de E/S


A sintaxe do símbolo de formatação "%" é:

"% [flag] [largura] [.precisão] [F|N|h|l|L] tipo de dado"

Em que:
Programação Básica com Linguagem C 252

Tabela 14.3 Componentes do formato de E/S e suas descrições


Componente Descrição
flags Alinhamento, sinais, pontos decimais, etc
largura Fixa largura de saída
precisão Número de casas no ponto flutuante
tipo de saída Conversão de tipos
formato Indica se a saída é do tipo inteiro, flutuante, caractere, string, etc

Tabela 14.4 Componente flag do formato de E/S e suas descrições


Flag Descrição
- Alinhamento à esquerda, preenchendo com brancos à direita. Se não for utilizado,
o texto é alinhado à direita, preenchendo-se à esquerda com zeros ou brancos
+ Sinaliza resultado numérico com o sinal de (+) ou de (-)
espaço Se o resultado for positivo, sinaliza com um branco. Se negativo, sinaliza com o
sinal de menos (-)
# Especifica que aquele argumento deve ser convertido utilizando-se uma maneira
alternativa

Tabela 14.5 Componente largura do formato de E/S e suas descrições


Largura Descrição
n Pelo menos n caracteres são impressos. Se o valor tiver menos caracteres que
n, preenche-se o resto com brancos
0n Pelo menos n caracteres são impressos. Se o valor tiver menos caracteres que
n, preenche-se o resto com zeros
* A lista de argumentos fornece a largura, que deverá preceder o verdadeiro
argumento a ser formatado

Tabela 14.6 Componente precisão do formato de E/S e suas descrições


Precisão Descrição
Precisões default:
• 1, para os tipos d, i, o, u, x, X
• 6, para os tipos e, E, f
Todos os dígitos significativos para os tipos g, G
Imprima o primeiro caractere nulo dos tipos s
Sem efeito, para os tipos c
0 Para os tipos d, i, o, u, x, X, a precisão é ajustada para a default
Para os tipos e, E, f, nenhum ponto decimal é impresso
n n caracteres ou n casas decimais. Se o resultado tiver mais de n caracteres, o
resultado será truncado ou arredondado (isto depende do tipo do caractere)
* A lista de argumentos fornece a largura, que deverá preceder o verdadeiro
argumento a ser formatado
Programação Básica com Linguagem C 253

Tabela 14.7 Componente tipo de saída do formato de E/S, tipos de argumentos e


sua interpretação
Tipo de Saída Tipo de Argumento Argumento é interpretado como
F Ponteiro (P, s, n) pointer
N Ponteiro (P, s, n) pointer
h diouxX short int
l diouxX long int
l eEfgG double
L eEfgG long double

Tabela 14.8 Componente formato do formato de E/S, seus tipos e sua descrição
Formato Tipo Descrição
d inteiro inteiro sinalizado
i inteiro inteiro sinalizado
o inteiro octal não sinalizado
u inteiro inteiro não sinalizado
x inteiro hexadecimal, com letras minúsculas
X inteiro hexadecimal, com letras maiúsculas
f ponto flutuante valor sinalizado de ponto flutuante
e ponto flutuante valor sinalizado de ponto flutuante em notação científica
g ponto flutuante alterna para f ou e, dependendo da formatação
E ponto flutuante valor sinalizado de ponto flutuante em notação científica
G ponto flutuante idem de g para e
c caractere um simples caractere
s string imprime uma cadeira de caracteres até que se encontre o
caractere "NULL"
% imprime o caractere %
n ponteiro para int armazena (no local apontado pelo argumento de entrada) a
quantidade de caracteres escritos desde então
p ponteiro imprime o argumento de entrada como um ponteiro

Formato para número inteiro que tenha sempre 3 dígitos:

int idade = 15;


printf( "\nIdade: %03d anos", idade );

Formatar para número real que tenha 2 casas decimais:

double peso = 45.12;


printf( "\nPeso: %.2f kg", peso );

Pesquise na wikipédia: sintaxe printf C

14.5. Portas Lógicas


Programação Básica com Linguagem C 254

Portas ou circuitos lógicos são dispositivos que operam e trabalham com um ou


mais sinais lógicos de entrada para produzir uma e somente uma saída São em
circuitos eletrônicos. O comportamento das portas lógicas é conhecido pela tabela
verdade que apresenta os estados lógicos das entradas e das saídas,Tabela 14.9.

Tabela 14.9 Portas lógicas com seus símbolos e tabela verdade


Tipo Símbolo Tabela Verdade
Entrada Saída
A B A AND B
0 0 0
AND
0 1 0
1 0 0
1 1 1
Entrada Saída
A B A OR B
0 0 0
OR
0 1 1
1 0 1
1 1 1
Entrada Saída
A NOT A
NOT
0 1
1 0
Entrada Saída
A B A NAND B
0 0 1
NAND
0 1 1
1 0 1
1 1 0
Entrada Saída
A B A NOR B
0 0 1
NOR
0 1 0
1 0 0
1 1 0
Entrada Saída
A B A XOR B
0 0 0
XOR
0 1 1
1 0 1
1 1 0
Entrada Saída
A B A XNOR B
0 0 1
XNOR
0 1 0
1 0 0
1 1 1

Exemplo 14.3 Dado o circuito lógico abaixo, faça um programa em C para calcular
a saída s em função das suas entradas.

Este circuito possui 3 portas:


Programação Básica com Linguagem C 255

1. NOT – tem entra a e saída pa, pa = !a (Tabela 14.9)


2. OR – tem entras pa e b e saída pb, pb = pa || b
3. AND – tem entras pb e c e saída s, s = pb && c

#include <stdio.h>
int main( void ){
int a, b, c, pa, pb, s;

printf("\n\n Entre com o valor do pino: 0 ou 1 \n\n");

printf("Pino de entrada a: ");


scanf("%d", &a);
printf("Pino de entrada b: ");
scanf("%d", &b);
printf("Pino de entrada c: ");
scanf("%d", &c);

pa = !a;
pb = pa || b;
s = pb && c;

printf("Pino s = %d", s );
return 0;
}
Há outras maneiras de modelar problemas de circuito lógico, estes é um deles.

Outra solução para o Exemplo 14.3.

Exemplo 14.4 Dado o circuito lógico abaixo, faça um programa em C para calcular
a saída s em função das suas entradas.

Este circuito possui 3 portas:

4. NOT – tem entra a e saída pa, pa = !a (Tabela 14.9)


5. OR – tem entras pa e b e saída pb, pb = pa || b
6. AND – tem entras pb e c e saída s, s = pb && c

#include <stdio.h>
int main( void ){
int a, b, c, pa, pb, s;

printf("\n\n Entre com o valor do pino: 0 ou 1 \n\n");


Programação Básica com Linguagem C 256

printf("Pino de entrada a: ");


scanf("%d", &a);
printf("Pino de entrada b: ");
scanf("%d", &b);
printf("Pino de entrada c: ");
scanf("%d", &c);

pa = a == 1 ? 0 : 1;
pb = (pa == 1) || (b == 1) ? 1 : 0;
s = (pb == 1) && (c == 1) ? 1 : 0;

printf("Pino s = %d", s );
return 0;
}
Esta solução usa o comando ternário.

Mais outra solução para o Exemplo 14.3.

Exemplo 14.5 Dado o circuito lógico abaixo, faça um programa em C para calcular
a saída s em função das suas entradas.

Este circuito possui 3 portas:

7. NOT – tem entra a e saída pa, pa = !a (Tabela 14.9)


8. OR – tem entras pa e b e saída pb, pb = pa || b
9. AND – tem entras pb e c e saída s, s = pb && c

#include <stdio.h>
int main( void ){
bool a, b, c, pa, pb, s;

printf("\n\n Entre com o valor do pino: 0 ou 1 \n\n");

printf("Pino de entrada a: ");


scanf("%d", &a);
printf("Pino de entrada b: ");
scanf("%d", &b);
printf("Pino de entrada c: ");
scanf("%d", &c);

pa = !a;
pb = pa || b;
s = pb && c;
Programação Básica com Linguagem C 257

printf("Pino s = %d", s );

return 0;
}
Esta solução usa o tipo de dado bool.

Exercício 14.1 Faça um programa em C com uma função para calcular a saída de
cada um dos circuitos lógicos abaixo:

a)

b)

c)

d)

e)

f)
Programação Básica com Linguagem C 258

g)

h)

i)

j)

Pesquise na wikipédia: circuitos lógicos

14.6. Revisão de Matrizes


Programação Básica com Linguagem C 259

Matriz é uma tabela de linhas e colunas de valores de mesmo tipo. As matrizes


são muito utilizadas para a resolução de problemas de Engenharia.
Seja uma matriz A de m linhas e n colunas. Esta matriz é representada em
termos da linguagem C como:

a0,0 a0,1 a0,2 ⋯ a0 , n−1

[
A= a1,0

a1,1

a1,2

am−1,0 am −1,1 am −1,2
⋯ a1 ,n−1
⋱ ⋮
⋯ a m−1 ,n−1

As linhas são ordenadas verticalmente e numeradas de cima para baixo, são


]
indicadas pelo primeiro índice. A matriz A possui m linhas.
As colunas são ordenadas horizontalmente e numeradas da esquerda para
direita, são indicadas pelo segundo índice. A matriz A possui n colunas.

Exemplo 14.6 Exemplo de matriz 3x4.


−2 1 0 3
[
A= 5 3 0 −1
−1 2 1 −2 ]
A Figura 14.4 é uma representação estrutura de uma matriz A m,n, com suas
linhas, colunas e suas posições, nomenclatura dos seus índices e sua variação
dentro da tabela de dados.

Figura 14.4 Estrutura de uma matriz Am,n.

Pode-se observar os seguintes padrões em matrizes na linguagem C:

1. numa linha, os primeiros índices são fixos e os segundo variam


2. numa coluna, os segundos índices são fixos e os primeiros variam

Estes padrões são úteis para criar algoritmos para operações com matrizes, por
exemplo:

1. a linha 0 possui os elementos: a0,0 a0,1 a0,2 … a0,c … a0,n-1.


2. a linha 1 possui os elementos: a1,0 a1,1 a1,2 … a1,c … a1,n-1.
3. a linha l possui os elementos: al,0 al,1 al,2 … al,c … al,n-1, generalizando.
4. a coluna 0 possui os elementos: a0,0 a1,0 a2,0 … al,0 … am-1,0.
5. a coluna 1 possui os elementos: a0,1 a2,1 a2,1 … al,1 … am-1,1.
Programação Básica com Linguagem C 260

6. a coluna c possui os elementos: a0,c a1,c a2,c … al,c … am-1,c,, generalizando.

Estes padrões podem ser vistos na equação da matriz Am,n, abaixo:

a0,0 a0,1 a0,2 ⋯ a0 , c ⋯ a0 , n−1

[
a1,0
A= ⋮
al ,0

a1,1

al ,1

a1,2

al ,2

am −1,0 am −1,1 am −1,2
⋯ a1 ,c
⋮ ⋮
⋯ al , c
⋮ ⋮
⋯ a m−1 ,c
⋯ a1 , n−1
⋮ ⋮
⋯ al , n−1
⋮ ⋯
⋯ am−1 ,n−1
]
Dentre as operações com matrizes, destacam-se a soma, subtração e
multiplicação por número real.
Dadas as matrizes A e B:

a0,0 a0,1 a0,2 ⋯ a0 , n−1 b0,0 b0,1 b0,2 ⋯ b 0 ,n−1

[
A= a1,0

a1,1

a1,2

am−1,0 am −1,1 am −1,2
⋯ a1 ,n−1
⋱ ⋮
⋯ a m−1 ,n−1

A soma de A e B é uma outra matriz C, dada por:


] [
e B= b1,0

b1,1

b1,2

b m−1,0 bm−1,1 b m−1,2
⋯ b 1, n−1
⋱ ⋮
⋯ bm−1 ,n −1
]
a 0,0 +b0,0 a0,1 + b0,1 a0,2 +b0,2 ⋯ a 0 ,n−1 +b0 , n−1

[
C= a 1,0 +b1,0

a1,1 + b1,1

a1,2 +b1,2

a m−1,0 +bm−1,0 am −1,1 + bm−1,1 am−1,2 +bm −1,2

A subtração de A e B é uma outra matriz S, dada por:




a1 ,n−1 +b1 , n−1

⋯ a m−1 ,n−1 +bm −1 , n−1
]
a0,0 −b0,0 a0,1 −b0,1 a0,2 −b0,2 ⋯ a0 , n−1−b 0 ,n−1

[
S= a1,0 −b1,0

a1,1 −b1,1

a1,2 −b1,2

am−1,0 −bm−1,0 am−1,1 −bm −1,1 am−1,2 −bm−1,2


a 1, n−1−b1 , n−1

⋯ a m−1, n−1−b m−1, n−1

O produto de um número real k pela matriz A é uma outra matriz P, dada por:
]
k×a0,0 k×a 0,1 k ×a 0,2 ⋯ k ×a 0 ,n−1

[
P=kA= k×a1,0

k×a1,1

k ×a 1,2

k ×am −1,0 k ×am−1,1 k×am−1,2
⋯ k×a 1 ,n−1
⋱ ⋮
⋯ k ×am−1 , n−1 ]
2 1 0 0 1 3
Exemplo 14.7 Sejam

5A-3B.
[ ] [ ]
A= 5 3 0
1 2 1
e B= 1 2 2
2 0 2
, calcule C = A+B, S = A-B, P =

2+0 1+1 0+3 2 2 3

[
C= 5+1 3+2 0+2 = 6 5 2
1+1 2+0 1+2 2 2 3 ][ ]
Programação Básica com Linguagem C 261

2−0 1−1 0−3 2 0 −3


[
S= 5−1 3−2 0−2 = 4 1 −2
1−1 2−0 1−2 0 2 −1 ][ ]
5×2−3×0 5×1−3×1 5×0−3×3 10 2 −9
[
P= 5×5−3×1 5×3−3×2 5×0−3×2 = 2 9 −6
5×1−3×1 5×2−3×0 5×1−3×2 2 10 −1 ][ ]
Sejam as matrizes A = [al,c] e B = [bl,c], para 0 ≤ l < n e 0 ≤ c < m. Sejam C = A +
B, S = A – B e P = k A, para k real, logo, pode-se escrever C = [a l,c+bl,c], S = [al,c-bl,c]
e P = [kal,c], para 0 ≤ l < n e 0 ≤ c < m.

14.7. Palavras Reservadas da Linguagem C

Tabela 14.10 Palavras reservadas da Linguagem C

Palavra Uso
Tipos e afins
auto classe de armazenamento de variável
char tipo de dados utilizado para armazenar caracteres
const cria variável atribuindo um valor que não pode ser modificado
double tipo de dado numérico de ponto flutuante - precisão dupla
enum tipo de dados definido pelo programador
extern indica que a variável foi declarada em outro arquivo
float tipo de dado de ponto flutuante com precisão simples
int tipo de dado numérico para armazenar valores inteiros
long modificador de tipo de dado int e double
register classe de armazenamento de variável
short modificador de tipo de dado int
sizeof função que retorna o tamanho do argumento
signed modificador de tipo de dado int e char
static classe de armazenamento de variável
struct cria estruturas
typedef cria novo nome para tipos de dados
union cria unions
unsigned modificador de tipo de dado int e char
void19 tipo de dado que indica ausência de parâmetro ou argumento
volatile classe de armazenamento de variável
Controle e afins

19 O uso do void é bem mais sofisticado do que o descrito.


Programação Básica com Linguagem C 262

break força a saída dos comandos switch, for, while e do-while


case comando do switch para selecionar uma constante
continue força a interrupção dos laços for, while e do-while
default usado no switch
do parte do comando do-while
else parte opcional do comando if
for comando de repetição
goto faz desvio (uso não recomendado)
if comando condicional
return comando para retorno de função
switch comando de seleção
while comando de repetição
Programação Básica com Linguagem C 263

15. Terminologias Úteis

1. Alocar – destinar uma região da memória principal a uma variável ou constante para
uso exclusivo do programa de computador que a criou.
2. Arquivo Executável – arquivo no formato binário e pode ser executado por um
processador - CPU.
3. ASCII – American Standard Code for Information Interchange, é uma codificação de
caracteres de oito bits baseada no alfabeto inglês, utilizado para representar textos
em computadores, equipamentos de comunicação, entre outros dispositivos que
trabalham com texto.
4. Biblioteca Padrão – conjunto de funções que dão suporte a Programas C. Estas
funções incluem todas as operações de Entrada/Saída, bem como outras rotinas
úteis.
5. Bit – {0,1}, sinal elétrico ou magnético baixo (0) ou alto (1). Qualquer coisa que seja
dual, duplo, polarizado e que pode ser transformado em tecnologia.
6. Bloco – região do código delimitado por chaves, seu início começa com a chave
abrindo ({) e seu fim é definido pela chave fechando (}).
7. Booleano – valor lógico {false, true}.
8. Byte – conjunto de oito bits, octeto binário.
9. Classe de armazenamento – refere-se ao tempo de vida de uma variável (temporário
ou permanente)
10.Código Fonte – arquivo no formato de texto, escrito em uma linguagem de
programação.
11.Código Objeto – código gerado após a compilação do código fonte, código
intermediário pois deve ser processado pelo linker para gerar o arquivo executável
ou a biblioteca.
12.Condição – expressão booleana das estruturas condicional e de repetição.
13.Escopo – região que contém declarações, cada declaração adiciona um nome ao
escopo, estes nomes são visíveis apenas nesta região, fora dela são invisíveis. Para o
escopo local temos que a região é um bloco e no escopo global a região é o
programa ou um arquivo do programa.
14.Estrutura –
15.Flag - em programação são interruptores, podendo assumir os valores lógicos {false,
true}. São utilizados, em geral, em estruturas condicional e de repetição.
Programação Básica com Linguagem C 264

16.Fluxo de Controle – sequência contínua ordenada dos comandos dos programas de


computador, do seu início ao seu fim
17.Fluxograma - representa gráfica dos comandos que compõem um algoritmo.
18.GCC - GNU Compiler Collection é um conjunto de compiladores de linguagens de
programação produzido pelo projecto GNU, sendo uma das ferramentas
fundamentais para manter softwares livres, pois permite compilar códigos-fonte em
binários executáveis para as várias plataformas de hardware. É distribuído pela Free
Software Foundation (FSF) sob os termos da GNU GPL.
19.Linguagem de Programação – é qualquer linguagem artificial que pode ser usada
para definir uma sequência de instruções que podem vir a ser processada e
executada por computador.
20.Linker – programa que une módulos compilados separadamente em um programa.
Ele também combina as funções na biblioteca C padrão com o código escrito. A saída
do linker é um programa executável.
21.Operação – transformação associada aos tipos, podem ser lógicas ou aritméticas;
tem ainda aquelas relacionadas aos endereços de memória e itens de hardware.
22.Operador – símbolo de uma operação.
23.Programa de Computador – similar a Programa Executável.
24.Programa Executável - é uma sequência de comandos que podem ser executadas
por um computador. O termo pode referir-se ao código fonte original ou a linguagem
de máquina executável.
25.Tempo de Compilação – tempo durante o qual seu programa está sendo compilado.
26.Tempo de Execução – tempo durante o qual seu programa está sendo executado.
27.Tipo – {valor, operação}, abstração de algo, usado para representar conjuntos de
valores possíveis. Cada tipo possui suas operações correspondentes.
Programação Básica com Linguagem C 265

16. Bibliografia

Ascenio, A. F. G.; Campos, E. A. V. Fundamentos da Programação de


Computadores. 2ª ed. Editora Pearson Education, 2003.
Schildt, Herbert. C Completo e Total. Editora Pearson Makron Books, 2006.
Sebesta, Robert W. Conceitos de linguagens de programação. 9. ed. Porto
Alegre: Bookman, 2011.
Wikipédia
Programação Básica com Linguagem C 266

Potrebbero piacerti anche