Universidade Federal de Santa Catarina Centro Tecnológico Departamento de Automação e Sistemas Engenharia de Controle e Automação IndustrialVersão 2000/2 Prof. Marcelo Ricardo Stemmer
[email protected] DAS – CTC - UFSC Informática Industrial I DAS/UFSC SUMÁRIO 1 INTRODUÇÃO À INFORMÁTICA INDUSTRIAL E AOS SISTEMAS DE PRODUÇÃO AUTOMATIZADOS.................................................................................................................................. 9 1.1 AUTOMAÇÃO DE PROCESSOS CONTÍNUOS INDUSTRIAIS .............................................................. 10 1.2 AUTOMAÇÃO DE PROCESSOS DISCRETOS E DA PRODUÇÃO (AUTOMAÇÃO DA MANUFATURA) ... 11 1.3 A MANUFATURA INTEGRADA POR COMPUTADOR (CIM) ............................................................. 11 1.3.1 DEFINIÇÃO E OBJETIVOS ........................................................................................................... 11 1.3.2 MODELO CIM........................................................................................................................... 11 1.3.3 FERRAMENTAS COMPUTACIONAIS DE APOIO A CIM .................................................................. 13 2 EQUIPAMENTOS UTILIZADOS EM SISTEMAS AUTOMATIZADOS...................................... 15 2.1 EQUIPAMENTOS MECÂNICOS ........................................................................................................ 15 2.1.1 MÓDULOS DE PROCESSAMENTO E USINAGEM ............................................................................ 15 2.1.2 MÓDULOS DE TRANSPORTE E ARMAZENAMENTO...................................................................... 15 2.1.3 MÓDULOS DE MANUSEIO DE MATERIAIS E FERRAMENTAS ........................................................ 15 2.1.4 MÓDULOS DE MONTAGEM ........................................................................................................ 15 2.1.5 MÓDULOS DE CONTROLE DE QUALIDADE ................................................................................. 16 2.2 DISPOSITIVOS DE COMANDO E CONTROLE ................................................................................... 16 3 COMPUTADORES PC / IC............................................................................................................... 24 3.1 HISTÓRICO .................................................................................................................................... 24 3.2 ARQUITETURA DO PC.................................................................................................................... 24 3.3 PRINCIPAIS COMPONENTES ........................................................................................................... 25 3.3.1 BARRAMENTO DE DADOS E ENDEREÇOS ................................................................................... 25 3.3.2 FONTE DE ALIMENTAÇÃO DO PC ............................................................................................... 26 3.3.3 CONTROLADOR DE INTERRUPÇÕES ........................................................................................... 26 3.3.4 TIMER....................................................................................................................................... 27 3.3.5 CONTROLADOR DE DMA (DIRECT MEMORY ACCESS) .............................................................. 28 3.3.6 MEMÓRIAS ROM E RAM ......................................................................................................... 28 3.3.7 CONTROLADOR DE TECLADO .................................................................................................... 29 3.3.8 TECLADO .................................................................................................................................. 31 3.3.9 INTERFACE PARALELA .............................................................................................................. 33 3.3.10 INTERFACE SERIAL ................................................................................................................. 33 3.3.11 CONTROLADOR DE VÍDEO ....................................................................................................... 34 3.3.12 UNIDADES DE DISCO / DISQUETE ............................................................................................ 36 3.4 SOFTWARE BÁSICO DO PC ............................................................................................................ 41 3.4.1 SOFTWARE DA ROM................................................................................................................. 41 3.4.1.1 Rotinas de Inicialização...................................................................................................... 41 3.4.1.2 BIOS.................................................................................................................................. 41 3.4.2 O SISTEMA OPERACIONAL DOS (DISK OPERATING SYSTEM).................................................... 42 4 PROGRAMAÇÃO DO PC E DE SISTEMAS COMPUTADORIZADOS ....................................... 44 4.1 INTRODUÇÃO ................................................................................................................................. 44 4.2 CONCEITOS BÁSICOS DA PROGRAMAÇÃO EM C ........................................................................... 45 4.2.1 HISTÓRICO DE C ....................................................................................................................... 45 Marcelo Ricardo Stemmer 2 Informática Industrial I DAS/UFSC 4.2.2 CRIANDO UM PROGRAMA EXECUTÁVEL ................................................................................... 45 4.2.3 A ESTRUTURA BÁSICA DE UM PROGRAMA EM C ....................................................................... 46 4.2.4 VARIÁVEIS ............................................................................................................................... 48 4.2.5 TIPOS DE DADOS....................................................................................................................... 48 4.2.6 CONSTANTES ............................................................................................................................ 50 4.2.7 PONTEIROS ............................................................................................................................... 51 4.2.8 EXERCÍCIOS .............................................................................................................................. 52 4.3 ENTRADA/SAÍDA DO CONSOLE ...................................................................................................... 53 4.3.1 PRINTF() ................................................................................................................................... 53 4.3.2 CPRINTF()................................................................................................................................. 55 4.3.3 SCANF().................................................................................................................................... 56 4.3.4 GETCH(), GETCHE() E GETCHAR()............................................................................................. 57 4.3.5 PUTCH() OU PUTCHAR()............................................................................................................ 57 4.3.6 EXERCÍCIOS .............................................................................................................................. 57 4.4 OPERADORES................................................................................................................................. 58 4.4.1 OPERADORES ARITMÉTICOS ..................................................................................................... 58 4.4.2 OPERADORES RELACIONAIS...................................................................................................... 59 4.4.3 OPERADORES LÓGICOS BINÁRIOS .............................................................................................. 59 4.4.4 OPERADORES DE PONTEIROS .................................................................................................... 60 4.4.5 OPERADORES INCREMENTAIS E DECREMENTAIS ....................................................................... 60 4.4.6 OPERADORES DE ATRIBUIÇÃO .................................................................................................. 62 4.4.7 O OPERADOR LÓGICO TERNÁRIO .............................................................................................. 63 4.4.8 PRECEDÊNCIA ........................................................................................................................... 63 4.4.9 EXERCÍCIOS:............................................................................................................................. 63 4.5 LAÇOS............................................................................................................................................ 64 4.5.1 O LAÇO FOR ............................................................................................................................. 64 4.5.2 O LAÇO WHILE......................................................................................................................... 65 4.5.3 O LAÇO DO-WHILE .................................................................................................................. 66 4.5.4 BREAK E CONTINUE .................................................................................................................. 67 4.5.5 GOTO........................................................................................................................................ 67 4.5.6 EXERCÍCIOS .............................................................................................................................. 67 4.6 COMANDOS PARA TOMADA DE DECISÃO ...................................................................................... 68 4.6.1 IF .............................................................................................................................................. 68 4.6.2 IF-ELSE..................................................................................................................................... 69 4.6.3 SWITCH .................................................................................................................................... 69 4.6.4 EXERCÍCIOS .............................................................................................................................. 71 4.7 FUNÇÕES ....................................................................................................................................... 72 4.7.1 SINTAXE ................................................................................................................................... 72 4.7.2 EXEMPLOS ................................................................................................................................ 73 4.7.3 PROTOTIPAGEM ........................................................................................................................ 74 4.7.4 CLASSES DE ARMAZENAMENTO ................................................................................................ 75 4.7.4.1 Auto................................................................................................................................... 75 4.7.4.2 Extern ................................................................................................................................ 75 4.7.4.3 Static.................................................................................................................................. 76 4.7.4.4 Variáveis Estáticas Externas ............................................................................................... 77 4.7.4.5 Register.............................................................................................................................. 77 4.7.5 EXERCÍCIOS .............................................................................................................................. 77 4.8 DIRETIVAS DO PRÉ-PROCESSADOR ............................................................................................... 78 4.8.1 DIRETIVA #DEFINE .................................................................................................................... 78 4.8.2 MACROS ................................................................................................................................... 79 4.8.3 DIRETIVA #UNDEF .................................................................................................................... 80 4.8.4 DIRETIVA #INCLUDE ................................................................................................................. 80 4.8.5 COMPILAÇÃO CONDICIONAL..................................................................................................... 81 4.8.6 OPERADOR DEFINED ................................................................................................................. 81 4.8.7 DIRETIVA #ERROR .................................................................................................................... 82 Marcelo Ricardo Stemmer 3 Informática Industrial I DAS/UFSC 4.8.8 DIRETIVA #PRAGMA .................................................................................................................. 82 4.8.9 EXERCÍCIOS .............................................................................................................................. 82 4.9 MATRIZES ..................................................................................................................................... 82 4.9.1 SINTAXE DE MATRIZES ............................................................................................................. 83 4.9.2 INICIALIZANDO MATRIZES ........................................................................................................ 84 4.9.3 MATRIZES COMO ARGUMENTOS DE FUNÇÕES ........................................................................... 85 4.9.4 CHAMADA POR VALOR E CHAMADA POR REFERÊNCIA ............................................................. 87 4.9.5 STRINGS ................................................................................................................................... 89 4.9.5.1 Strings Constantes .............................................................................................................. 89 4.9.5.2 String Variáveis.................................................................................................................. 89 4.9.5.3 Funções para Manipulação de Strings ................................................................................. 90 4.9.6 EXERCÍCIOS .............................................................................................................................. 91 4.10 TIPOS ESPECIAIS DE DADOS ........................................................................................................ 92 4.10.1 TYPEDEF ................................................................................................................................. 92 4.10.2 ENUMERADOS (ENUM)............................................................................................................ 93 4.10.3 ESTRUTURAS (STRUCT)........................................................................................................... 94 4.10.4 UNIÕES ................................................................................................................................... 97 4.10.5 BITFIELDS ............................................................................................................................... 98 4.10.6 EXERCÍCIOS ............................................................................................................................ 99 4.11 PONTEIROS E A ALOCAÇÃO DINÂMICA DE MEMÓRIA ................................................................ 99 4.11.1 DECLARAÇÃO DE PONTEIROS E O ACESSO DE DADOS COM PONTEIROS.................................... 99 4.11.2 OPERAÇÕES COM PONTEIROS ................................................................................................ 100 4.11.3 FUNÇÕES & PONTEIROS ........................................................................................................ 102 4.11.4 PONTEIROS & MATRIZES ...................................................................................................... 103 4.11.5 PONTEIROS & STRINGS ......................................................................................................... 104 4.11.6 PONTEIROS PARA PONTEIROS ................................................................................................ 106 4.11.7 ARGUMENTOS DA LINHA DE COMANDO ................................................................................ 108 4.11.8 PONTEIROS PARA ESTRUTURAS ............................................................................................. 109 4.11.9 ALOCAÇÃO DINÂMICA DE MEMÓRIA .................................................................................... 110 4.11.9.1 Malloc() ......................................................................................................................... 111 4.11.9.2 Calloc() .......................................................................................................................... 112 4.11.9.3 Free() ............................................................................................................................. 112 4.11.10 EXERCÍCIOS ........................................................................................................................ 113 4.12 MANIPULAÇÃO DE ARQUIVOS EM C.......................................................................................... 113 4.12.1 TIPOS DE ARQUIVOS ............................................................................................................. 113 4.12.2 DECLARAÇÃO, ABERTURA E FECHAMENTO............................................................................ 114 4.12.3 LEITURA E ESCRITA DE CARACTERES..................................................................................... 115 4.12.4 FIM DE ARQUIVO (EOF)........................................................................................................ 115 4.12.5 LEITURA E ESCRITA DE STRINGS ............................................................................................ 116 4.12.6 ARQUIVOS PADRÃO .............................................................................................................. 116 4.12.7 GRAVANDO UM ARQUIVO DE MANEIRA FORMATADA ........................................................... 117 4.12.8 LEITURA E ESCRITA DE VALORES BINÁRIOS ........................................................................... 117 4.12.9 EXERCÍCIOS .......................................................................................................................... 118 4.13 PROGRAMAÇÃO EM C++ ........................................................................................................... 119 4.13.1 PALAVRAS-CHAVE EM C++ ................................................................................................... 121 4.13.2 SINTAXE & VARIÁVEIS ......................................................................................................... 121 4.13.3 LAÇOS E COMANDOS DE DECISÃO ......................................................................................... 122 4.13.4 I/O EM C++: STREAM............................................................................................................ 122 4.13.4.1 A stream de saída cout .................................................................................................... 122 4.13.4.2 A stream de entrada cin................................................................................................... 124 4.13.5 FUNÇÕES .............................................................................................................................. 125 4.13.5.1 Valores Default Para Argumentos de uma Função........................................................... 125 4.13.5.2 Sobrecarga de Funções ................................................................................................... 125 4.13.5.3 Funções Inline ................................................................................................................ 125 4.13.5.4 Operador Unário de Referência: &.................................................................................. 126 Marcelo Ricardo Stemmer 4 ........................ 172 5.............6 4. 169 ESCREVENDO E LENDO EM BUFFERS DE CARACTERES......................................................... 130 FUNÇÕES-MEMBRO..................................................................................................................................................14........................6 4......................................7 4......................16............................ 169 IMPRIMINDO EM PERIFÉRICOS ..................................................................................................................1 4................................................................ 173 5...........................2 4.............................17................16.................................................6 4.......................... 135 EXERCÍCIOS .............................................................................................3 HISTÓRICO............ 171 5 CONTROLADORES LÓGICOS PROGRAMÁVEIS (CLP....................................................................................... 164 OPERAÇÕES COM ARQUIVOS IOSTREAM ..............................................................................................................................8 4.............5 4......................................4 4..... 170 EXERCÍCIOS .......................18.............................................14.......................... 152 HERANÇA PÚBLICA E PRIVADA ................................................. 160 CLASSE-BASE VIRTUAL ......13...........14..16............................................................... 151 CONSTRUTOR DE CÓPIA & ALOCAÇÃO DINÂMICA ........17................................1 4.......................................... 133 ACESSANDO FUNÇÕES E DADOS PÚBLICOS ................................16...... 154 NÍVEIS DE HERANÇA ..... 129 MEMBROS PRIVADOS E PÚBLICOS ........14......16...................18 4....................16...............18.... 166 A FUNÇÃO OPEN() .....................................................................................................10 4...................................... 158 DESTRUTORES VIRTUAIS........................................................... 148 DADOS PROTECTED ........................................2 4.............................................16...........................................................3 4...15...............................................18........................... 173 5.............................................................................................. 172 5.....................................................................3 4........Informática Industrial I DAS/UFSC 4................... 138 ESTUDO DE CASOS ...................................................4 4......................................................... 162 CLASSES AMIGAS..............................................................................3 4........... 158 FUNÇÕES VIRTUAIS ............... 129 DEFININDO CLASSES ..................15.... 175 Marcelo Ricardo Stemmer 5 ...1 4............................................... 139 EXERCÍCIOS .......................17 4...........................1....................18.......................... 147 DERIVANDO UMA CLASSE ...........................................................................................................................................1 INTRODUÇÃO AOS CLPS ....... 154 HERANÇA MÚLTIPLA ..............................................................................16 4......... 127 CLASSES E OBJETOS EM C++ ..................... 134 OBJETOS CONST...............5 4.... 172 5..........2 ÁREAS DE APLICAÇÃO .................................................................................................2 ARQUITETURA DOS CLPS..2 4..........................2 4.................................................... 134 TIPO OBJETO ................................................................................ 161 FUNÇÕES AMIGAS ... 131 CRIANDO OBJETOS..................................6 ALOCAÇÃO DINÂMICA DE MEMÓRIA EM C++ .........................6 4................................................................................ 158 FUNÇÕES VIRTUAIS E AMIGAS ......14..............................14...........................9 4................................................. 154 EXERCÍCIOS ...........................................................................................16...4 4...13..............4 4. 132 ATRIBUTOS DO TIPO STATIC ......................................1 4..............................3 4........9 4............................................... PLC) ..........3 4......16.. 153 CONVERSÕES DE TIPOS ENTRE CLASSE-BASE E DERIVADA ...............................1 4.........17................14 4..........................................................................7 4.......15 4.................5 4............................ 163 EXERCÍCIOS .........15...................2 4.....18........................................................................................................................................4 4......................1......................................................14... 131 CONSTRUTORES & DESTRUTORES ...................5 4.................................................................17.................. 146 HERANÇA ....... 152 CHAMADAS A FUNÇÕES ..................................................11 4............................................................................................. 127 TIPO CLASSE E O ENCAPSULAMENTO DE DADOS ...14.................................................................................................................................................................................15...........................................................................14.5 4........................................................1.................................................................................................. 135 SOBRECARGA DE OPERADORES .....17.....10 4.....................................14.. 169 TESTANDO ERROS ...........16.............................. 126 EXERCÍCIOS .............. 138 SOBRECARGA DE OPERADORES COMO FUNÇÃO-MEMBRO . 151 CONSTRUTORES & DESTRUTORES ..............................................................................................18.....................................................15.................................7 4.............................................. 137 LIMITAÇÕES E CARACTERÍSTICAS .............................................................................. 172 5.....................................1 DEFINIÇÃO ..... 135 A SOBRECARGA COMO UMA FUNÇÃO GLOBAL ........................8 4...................... 164 ESTUDO DE CASO ...........................................................................3 FORMAS DE INTERFACEAMENTO HOMEM/MÁQUINA PARA CLPS .............17....................................................14..... . 220 9 BIBLIOGRAFIA ....................................... 179 5................................................1 6.................5 Diagramas equivalentes....................................................................................... 222 C/C++ ..............................................................................................................2 INTERFACEAMENTO POR MEIO DE PAINÉIS INTELIGENTES ............................................... 212 5...............9 O MERCADO DE CLPS NO BRASIL ........... 216 6....... 186 5................ 208 5................................................ 219 8 ANEXO II – TRABALHO DE CLP......4 LADDER DIAGRAMM (LD) ............. 216 ATUADORES INTELIGENTES ..................... 197 5..................................4........4....................4......................3 INTERFACEAMENTO POR MEIO DE TERMINAIS DE PROGRAMAÇÃO (TP)...........4......7 NORMAS RELEVANTES PARA CLPS ......... 188 5.................................................................................................................... 200 5............................3 CLP .......................................................................3 INSTRUCTION LIST (IL) .2 Elementos básicos do LD ................1 INTERFACEAMENTO POR MEIO DAS ENTRADAS E SAÍDAS DO CLP .....................2 Elementos básicos do GRAFCET ............ 212 5..... 192 5........................ 175 5...................................................................................................................................................................1 Introdução ..................................................... 185 5...................................... 188 5..............................................2 REVISÃO DE ÁLGEBRA BOOLEANA ......................................... 190 5................. 188 5..........................................6...... 180 5...............4 Vantagens e desvantagens da técnica .............................................................. 202 5........................................................................... 188 5...................................................... 210 5............................3 Estrutura de um programa em LD ........6....4 INTERFACEAMENTO POR INTERMÉDIO DE COMPUTADORES TIPO PC / IC...............................6...........................................6....................................6....................6........ 177 5..............................................................................2 SENSORES INTELIGENTES .......................................... 185 5........................................6 PROGRAMAÇÃO DE CLPS ..........................5.........................................................................................................5.........3................................................................................................6......6.........6..................6......7 Vantagens da técnica ..8 INTERLIGAÇÃO DE CLPS UTILIZANDO REDES DE COMUNICAÇÃO .......................... 185 5...................................................................6 Exemplo de programação em GRAFCET ................. 224 Marcelo Ricardo Stemmer 6 .........4 Operandos e Instruções de LD .....5 GRAFOS DE COMANDO ETAPA-TRANSIÇÃO (GRAFCET...3...................... 204 5...4 MÓDULOS DE ENTRADA E SAÍDA ...5...................................... 178 5....3 Exemplo de programação em IL ............................................................... 196 5.. 206 5..........................................................3 Regras de Evolução do GRAFCET.....................5...........................................5......6.....................3..................................................2 Elementos básicos ............. 222 9.....................................................................................................................................1 Introdução ......................1 9............................................... 182 5..................................................6............................. 213 5........................ 180 5.............................6................................. 201 5...........................................................2 9.............................1 INTRODUÇÃO ..7 Vantagens e desvantagens da técnica ............6......3..............4........................3........ 223 HOT SITES .............................5............................................................................3...........Informática Industrial I DAS/UFSC 5..................... 214 6 SENSORES E ATUADORES INTELIGENTES.6..................................................................................................5 ORGANIZAÇÃO INTERNA DE MEMÓRIA ..........................................................................1 Introdução .... SFC) ...........................4.....................................6..........6...4......6........................................................ 201 5........................................3.................. 217 7 ANEXO I – TRABALHOS EM C/C++ .............. 176 5...........................6.....................6................6...............................4 Estruturas lógicas em GRAFCET ...6 Exemplos de programação em LD ........5.............................6............................................................................. 177 5...........6..............................3........5 Análise e validação do GRAFCET ........................................ ......................................formato de uma lógica.............................................19 Figura 9 ..........CLP com módulos de expansão..................................................................................................10 Figura 3 – Controle Digital........ ..........................................................Hierarquia das Classes Iostream do Compilador Borland C++ 4............................................................Lógica "E": (a) com relês......... ...................................................... (c) a transistor coletor aberto.......................................................................................................... 191 Figura 47 .......................Teclado do PC...............................................................................................14 Figura 6 ......................................... 180 Figura 37 – O ciclo de varredura de um CLP............................................39 Figura 25 ..... 179 Figura 36 ....Tabelas de E/S e de dados.....................................Comando de uma furadeira............................................................Interface Paralela.......Relês e elementos básicos de Diagramas de Escada.......................................... (b) em diagrama de escada........................................... .................Relação entre as ferramentas computacionais de apoio no ambiente CIM ......33 Figura 19 .................................)...................................Módulos de Montagem.33 Figura 20 ............. .................................Controlador de Teclado no PC.....................................Ilustração do processo de criação de um programa em C.......30 Figura 17 ..............Módulos de Transporte e Armazenamento............... ...................... ........Lógica "OU": (a) com relês.................. ................................ 193 Figura 48 .....5....................................... 191 Figura 46 ...............Painel "Inteligente"............................Barramentos no PC...22 Figura 12 ......................40 Figura 26 .... .................31 Figura 18 .................................Unidade de Disquete..Interface Serial..Exemplos de símbolos gráficos do Diagrama de Escada (LD) ..................Módulos de Processamento e Usinagem............................. (b) em diagrama de escada.......Módulos de Controle de Qualidade.................................................................Interfaceamento com operador via E/S do CLP................................. .................................Fator de Interleave...................21 Figura 11 ..........................Módulos de Transporte e Armazenamento (cont..20 Figura 10 ...............................Ligação em série de uma bobina........................................................................................................................................................................................... 188 Figura 41 ...............................................................................................................25 Figura 15 ........................................... 181 Figura 38 ............. ..................... 190 Figura 44 ......................... .................................................. ...............................................23 Figura 13 ............................ ...............................Controlador de disco.............Informática Industrial I DAS/UFSC ÍNDICE DE FIGURAS Figura 1 – O âmbito da informática industrial..........................................37 Figura 23 .........................Placa Mãe de um PC/XT................................... (b) Diagrama Escada...........................................Módulos de Manuseio de Materiais e Ferramentas........24 Figura 14 . 187 Figura 40 ..................................Terminais de Programação para CLP............................. ..Arquitetura interna do PC....................................)......................................37 Figura 24 ...... 172 Figura 30 ....... 189 Figura 42 ..............10 Figura 2 – Controle em malha fechada....Configuração básica de um CLP................. ... 177 Figura 35 – Saídas: (a) A relê..................................................................... 147 Figura 28 ................ .................................................................................................... ................................. 175 Figura 32 ......................................................Estrutura de dados de um disco....................................18 Figura 8 ....................Módulos de Processamento e Usinagem (cont.......................................34 Figura 21 – Byte de atributo em modo texto....................... .........................................................................................................Arquitetura interna dos CLPs......................Exemplo de Diagrama de Escada..Contador simples... .............17 Figura 7 .. .......................... 165 Figura 29 ............................ (a) Relês.......35 Figura 22 ........Modelagem aplicando-se o princípio da Herança........... 190 Figura 45 ................................................................................................. 189 Figura 43 .........................................Lógica de comando com portas lógicas digitais..................... 175 Figura 33 .................. ........................46 Figura 27 ......................27 Figura 16 ......................Contador Bidirecional................Controlador de Interrupções no PC................. 194 Marcelo Ricardo Stemmer 7 ..........................................................................................11 Figura 4 – Modelo CIM............ 185 Figura 39 ............................................................... 177 Figura 34 ................................... 174 Figura 31 ........ (b) A TRIAC.................................................................. ....12 Figura 5 ...................... ...................Configuração básica de um Sensor inteligente.....................................................Esquema do estacionamento a ser controlado...................................................................................Disparo múltiplo (a) antes........ 196 Figura 56 .................... 200 Figura 60 ................................................................ ........................................................ ........................................................................ 210 Figura 81 ....................................................................................... 197 Figura 57 ..............Programa em LD para o estacionamento........................................ 198 Figura 58 ...... 205 Figura 71 ........................................................ 205 Figura 72 ............... 205 Figura 70 ..............Faturamento do setor de CLPs no Brasil (1986-1992).................................................Condição inicial do grafo.............................. (b) GN.................................................... ............ 202 Figura 62 ................Convergência em OU (a) GO....... (b) depois.... 195 Figura 53 ............................................................................... 220 Figura 90 ..................... 195 Figura 54 ................ 203 Figura 65 ...............................Misturador de Tintas (2 côres).................................... 203 Figura 64 ........................... 217 Figura 88 ....................... 204 Figura 68 ...... 221 Marcelo Ricardo Stemmer 8 .................................................. 215 Figura 86 ......................................................Transições e suas receptividades....................................... 194 Figura 50 ........... 211 Figura 82 ........Arcos (GO)....Receptividade incondicional.........Configuração básica de um Atuador Inteligente............................................. ................................................ 207 Figura 76 ..........Etapa com realimentação.......... ............ 206 Figura 74 ..............Arcos de entrada e saída...........Divergência em E (a) GO.....................Cruzamento com sinaleiras...... 199 Figura 59 ................ (b) Grafo determinado via intertravamento.......................................................................................................... ..................... 209 Figura 78 – Conflito resolvido (estrutura tipo IF ..................................................... 203 Figura 66 .................Conexões de Entrada e Saída no CLP....... ...................... ........... (b) depois.............Diagrama de Escada para o comando da sinaleira............... ................Convergência em E (a) GO.GRAFCET (GN) para o comando do sistema de transporte......... ........................... 206 Figura 73 ....... .........ELSE).................. 214 Figura 85 ............... .........Receptividade tempo...................... .................................... 209 Figura 79 – Etapas A e B em Paralelo......................CLP com módulo para interligação em rede.................................. 201 Figura 61 .....Operações OR............SDCD com CLPs interligados via rede............................................................................ 218 Figura 89 ......................Disparo simples (a) antes...........................................Grandezas a medir na automação........... 213 Figura 84 . 202 Figura 63 ...............................................................................................................................................Diagrama não representável no CLP..................... 216 Figura 87 ........... ..... .......Conexões de Entrada e Saída no CLP ........................................................................................ 204 Figura 69 . 195 Figura 52 – Divisão................................................................................... ..... ...........Etapa (a) desativada........ (b) incondicionais................... ...........................................Ações (a) condicionais........................... (b) GN......................................................Soma e Multiplicação. XOR.......................Sistema de transporte com AGV............................................................................................................................................................................................................. 209 Figura 80 – (a) Grafo não Determinado...... (b) GN.......... 207 Figura 75 ......................................THEN ............ 204 Figura 67 .... (b) ativada........................Divergência em OU (a) GO............. 212 Figura 83 ....................................... ............Informática Industrial I DAS/UFSC Figura 49 – Temporizador.... ..........................................Exemplo de receptividade tempo.................................................................... 194 Figura 51 – Subtração.... (b) GN............................. 196 Figura 55 .......................................................................................Diagrama equivalente ao exemplo anterior.... 208 Figura 77 – Transições A e B em Conflito..................................... AND................... as máquinas.Informática Industrial I DAS/UFSC 1 Introdução à Informática Industrial e aos Sistemas de Produção Automatizados Em tempos antigos. A introdução das primeiras tecnologias de automação (onde o homem é substituído pela máquina) em sistemas industriais de produção (por exemplo. As máquinas-ferramenta operam por Comando Numérico Computadorizado (CNC). Tais sistemas requerem técnicas especiais de programação. a era industrial só teve início em torno de 1800). e mesmo o homem foi substituído em muitas funções por robôs programáveis. a uma saturação do mercado mundial no século XX. possibilitando o surgimento da chamada Automação Flexível. Também foram introduzidos sistemas computacionais que permitem a programação de aplicações compartilhadas por vários computadores. sem necessidade de reestruturar o hardware (isto é. e esta tendência é claramente crescente. portanto. A resposta do mercado a esta saturação foi a exigência de maior diversificação e individualização dos produtos. um ramo da informática que compreende toda aplicação de sistemas computacionais em automação industrial. Muitas aplicações exigem também soluções diferentes das convencionais e levaram ao uso de técnicas de Inteligência Artificial em alguns subsistemas. Esta necessidade levou ao desenvolvimento das Redes Locais Industriais de comunicação. de forma a permitir a realização prática de verdadeiras fábricas automáticas. que englobe as últimas inovações tecnológicas. Enquanto as tecnologias antigas eram concentradas no estudo das melhores formas de manipulação de energia e de materiais. os processos contínuos são controlados em malha fechada por controladores digitais programáveis. Pode ser vista. que é baseada na idéia de equipamentos programáveis. A informática industrial é. a mais longo prazo. com a chamada Revolução Industrial. o que pode ser visto como um dos primeiros efeitos da automação da produção. a economia de todas as civilizações e culturas era fortemente baseada na agricultura e no comércio. Esta mesma produção em massa conduziu. Marcelo Ricardo Stemmer 9 . vem ocorrendo uma crescente exigência de qualidade por parte do mercado. formando os chamados Sistemas Distribuídos. as máquinas a vapor) conduziu a um grande aumento de produtividade e possibilitou a produção em massa de uma variada gama de produtos. Hoje temos sistemas computacionais em praticamente todos os setores de uma fábrica. além de ter uma vida útil menor. pois a cada ano o consumidor deseja um produto novo. portanto. por exemplo. desenvolvimento e produção. Todos estes equipamentos tem que poder trocar informações entre si. e chegou posteriormente a vários outros países (nos EUA. As técnicas originais de automação utilizadas na produção em massa não apresentam soluções bem adaptadas a estas novas exigências. Esta produção em massa contribuiu também para tornar os produtos mais baratos e acessíveis a um público consumidor muito maior. com muito baixa produtividade. as novas tecnologias de automação flexível estão concentradas na manipulação da informação. como informática aplicada à automação de sistemas industriais de produção e gerência (ver Figura 1). que passaram a requerer um menor tempo de projeto. Paralelamente a isto. tais como a Programação Concorrente. A tecnologia da Informática veio a fornecer a necessária reestruturação do setor produtivo. equipamentos e linhas de produção em si). Estes equipamentos se caracterizam por poderem ter sua função e operação alterada modificando apenas o software. as tecnologias de comando usando relês foram substituídas por Controladores Lógicos Programáveis (CLP). Este período teve início com a invenção da máquina a vapor na Inglaterra. Toda produção de bens de manufatura era baseada no trabalho artesanal. os sensores e atuadores são dotados de capacidade local de processamento (microprocessadores e microcontroladores). por volta de 1750. O início do período industrial deu-se somente no século XVIII. Inteligência Artificial (Sistemas Especialistas. A automação industrial divide-se em dois grandes setores: • Automação de Processos Contínuos de Produção • Automação da Manufatura (sistemas discretos de produção) 1. Devido a complexidade de tais sistemas industriais. A automação de processos contínuos industriais envolve a medição de grandezas físicas (por meio de sensores). Sistemas de Supervisão e Gerência. A automatização de tais processos requer essencialmente a utilização de conhecimentos na área de sistemas de controle. etc. será dada uma visão geral e introdutória à Automação Industrial. Valor de Referência Controlador Atuador Processo Sensor Realimentação (Feedback) Grandeza Controlada Figura 2 – Controle em malha fechada. de forma contínua no tempo (Figura 2). bateladas. o processamento da informação (por meio de controladores. etc.1 Automação de Processos Contínuos Industriais Os processos contínuos industriais se caracterizam pela produção não individualizada de bens.Informática Industrial I DAS/UFSC Automação Industrial Informática Informática Industrial Figura 1 – O âmbito da informática industrial. Programação de diversos equipamentos "inteligentes" (CLP. isto é. Redes Neurais. lotes.). Programação para Sistemas em Tempo Real. No presente curso daremos ênfase ao aspecto da informática industrial ligado à programação de alguns equipamentos "inteligentes".) e a correção do comportamento das grandezas de forma a seguir um sinal de referência desejado (por meio de atuadores) em malhas fechadas com realimentação. cada um em si bastante complexo e incluindo novas tecnologias. etc. de forma a melhor situar neste contexto os equipamentos cujo funcionamento e programação serão estudados. a Informática Industrial engloba conhecimentos de diversos sub-ramos. podemos citar: Sistemas Distribuídos. etc. RC. etc. A produção não é medida em unidades. Marcelo Ricardo Stemmer 10 . Antes disto. Entre estes. o produto a ser produzido é gerado de forma contínua. CNC. Redes de Computadores (LANs).). computadores. mas em volume. de acordo com uma estrutura piramidal. mas com a introdução do computador em todos os departamentos da fábrica.2 Automação de Processos Discretos e da Produção (Automação da Manufatura) Em processos discretos de produção (manufatura). Naval. Calçados. apresentada na Figura 4. O processo de produção como um todo não está submetido a um controle contínuo em malha fechada. velocidade. Siderurgia. Marcelo Ricardo Stemmer 11 . como mostrado na Figura 3. Têxtil. o modelo CIM propõe que a fabrica seja subdividida em diferentes níveis hierárquicos. A tendência aqui é o uso do controle digital. na Indústria química. Eletrodomésticos. por exemplo.3 A manufatura Integrada por Computador (CIM) 1. D/A Co mp utador A/D Sensor Atuador Processo Grande za Controlada Figura 3 – Controle Digital 1. os objetos produzidos são sempre produtos individualizados. força. onde um computador exerce a função de controlador. O projeto dos controladores utilizados baseia-se em regras para a obtenção de modelos matemáticos dos sistemas a controlar. Aeronáutica. etc.Informática Industrial I DAS/UFSC Processos industriais contínuos são encontrados. Sistemas de geração e distribuição de energia. torque. etc. Petroquímica. 1.1 Definição e objetivos A filosofia CIM (Computer Integrated Manufacturing) visa automatizar de forma flexível todos os processos envolvidos com a manufatura através da aplicação adequada de sistemas elétricos/eletrônicos. a partir dos quais é feita a determinação dos parâmetros dos controladores (Teoria de Controle e Servomecanismos). tem-se conseguido um melhor controle da produção. computacionais e de comunicação (troca de informações).3. Peças. São exemplos de sistemas discretos de produção: industria Automobilística. A manufatura envolve diversos subsistemas: • • • • • Usinagem e processamento de peças → máquina-ferramenta Montagem das peças isoladas em peças e produtos finais → linha de montagem Teste e medição das peças → controle de qualidade Transporte e armazenamento das peças Manuseio das peças e ferramentas para carga e descarga das máquinas → manipuladores e robôs O controle em malha fechada é utilizado em todos estes subsistemas (controles de posição. 1.).3.2 Modelo CIM Para permitir uma maior eficiência neste processo de Automação Flexível. etc. Metalurgia (metais não ferrosos). consumo de energia. reles. CAE... Cada um dos níveis hierárquicos indicados na Figura 4 tem suas funções: Tarefas do nível 0: Componentes • • • • aquisição de dados. CAPP. matéria-prima.. etc. o uso de matéria prima. CLP CNC Controle Fisico Componente (Component) S A S A Motores. Controle da Produtividade Area (Shop) FMS Chao de fabrica FMC Torno. Centro usinagem. etc.. energia e insumos e transferir ao nível 2 Tarefas do nível 2: Células (agrupamento lógico de unidades) • • • • • coletar e manter dados de produção. alarmes controle em malha fechada atuação fornecimento de informações ao nível 1 Tarefas do nível 1: Subsistemas ou Unidades (máquinas. monitoração. CAP..Informática Industrial I DAS/UFSC Nivel Hierarquico Administracao corporativa Controle da lucratividade Planejamento (Factory) Gw CAD.. CAQ.. robôs.) • • • • • controle do processo ou da máquina processamento e fornecimento de dados aos operadores detectar e responder a qualquer condição de emergência realizar auto-diagnósticos coletar informações sobre a produção da unidade. estoques das unidades otimizar a operação conjunta das unidades sob seu controle (sequênciamento e intertravamento) responder à condições de emergência realizar diagnósticos dos elementos sob controle interface com nível superior 12 Marcelo Ricardo Stemmer . Manipulador. etc. etc.. chaves. Figura 4 – Modelo CIM. Celula (Cell) MgU Subsistema (Subsystem) . Computer Aided Design • • projeto (desenho) do produto definição dados geométricos (formas. etc.Informática Industrial I DAS/UFSC Tarefas do nível 3: Área • • • • • • interconectar células entre si.controle de qualidade Tarefas do nível 5: Administração Corporativa • manter interfaces.3 Ferramentas computacionais de apoio a CIM CAD .estoques de produtos acabados . torção.) • simulação de processos → elementos finitos (por exemplo. processar e armazenar dados sobre . tolerâncias.) • fornecer informações p/ decisões estratégicas da companhia • interfaceamento com níveis inferiores da hierarquia e com o mundo externo 1. dimensões.3. compondo sistemas flexíveis de manufatura (FMS) manter base de dados de produção. vendas. estoques.) escolha da ferramenta.consumo global de energia . estoques . etc.uso e disponibilidade de matéria-prima.atividades de pessoal administrativo (compras. etc. (dados tecnológicos) usa técnicas de inteligência artificial gera plano do processo 13 Marcelo Ricardo Stemmer . tornear. matéria-prima.) CAE . contabilidade. furar. utilização de materiais.Computer Aided Engineering • análise de engenharia: análise da adequação da peça para funções previstas (resistência à deformações. velocidade de corte. conformação mecânica) CAPP .gerenciamento da planta e da companhia . etc. fornecer informações sobre estado da planta. tração.Computer Aided Process Planning • • • • determinar processo adequado à fabricação da peça (fresar. insumos e energia preparação e emissão de relatórios de produção estabelecer programa de produção imediato para as células da área otimizar plano de produção da área interface com nível superior e inferior Tarefas do nível 4: Planejamento da planta • • • • planejar e projetar o produto e o processo de fabricação estabelecer plano de produção básico determinar níveis ótimos de estoques coletar. da companhia e da produção necessários para: . etc. Informática Industrial I DAS/UFSC CAM . a garantia da qualidade do produto final usa técnicas como controle estatístico do processo (SPC.Computer Aided Quality (-Assurance) • • • • supervisão e análise do comportamento e desempenho do sistema detecção de erros e suas causas visa. CEP) Estas ferramentas computacionais se interrelacionam conforme mostrado na Figura 5.Computer Aided Production • controle de estoque • controle de fluxo de material • prioridades e prazos para linhas de produção CAQ .Relação entre as ferramentas computacionais de apoio no ambiente CIM Marcelo Ricardo Stemmer 14 . a nível de planejamento.Computer Aided Manufacturing • controle e supervisão do processo de fabricação em si • interage com as máquinas • geração dos programas NC (código G) CAP . ATIVIDADES LIGADAS AO PRODUTO E AO PROCESSO CAE BASE DE DADOS CAD CAPP CAP CAM FMC ATIVIDADES LIGADAS À PRODUÇÃO CAQ Figura 5 . Informática Industrial I DAS/UFSC 2 Equipamentos utilizados em sistemas automatizados Os equipamentos apresentados aqui se restringem à automação de processos discretos de produção (manufatura).de forma ordenada (Magazine) • dispositivos para mudança de local e posição .1 Equipamentos Mecânicos Os principais equipamentos mecânicos utilizados em sistemas automatizados de produção (para a automação da manufatura) são: 2.veículos guiados automaticamente (AGV) Estes módulos estão exemplificados na Figura 8 e Figura 9.conveyor tipo esteira . aplainamento.conveyor tipo rolo . manuseio. 2. montagem.1 Módulos de processamento e usinagem • máquinas operatrizes para torneamento. encontrados em processos contínuos.. 2. caldeiras. etc. mandrilamento.1. Marcelo Ricardo Stemmer 15 .1. 2. etc. fresagem.sistemas de corrente . Não faremos referência a fornos industriais. • prensagem para processos de conformação mecânica • centros de usinagem • Células e Sistemas Flexíveis de Manufatura (FMC.1.1. furação. FMS) Estes módulos estão exemplificados na Figura 6 e Figura 7.2 Módulos de Transporte e Armazenamento • dispositivos para armazenamento de peças: . 2. pintura.de forma não ordenada (Bunker) . usinagem e processamento) Estes módulos estão exemplificados na Figura 10. misturadores.3 Módulos de Manuseio de Materiais e Ferramentas • manipuladores manuais (teleoperadores) • manipuladores programáveis (“Pick and Place”) • robôs industriais (usados para solda.4 Módulos de Montagem • difíceis de automatizar • concebidos para operadores humanos • linhas de montagem → indústria automobilística → uso de robôs Estes módulos estão exemplificados na Figura 11. serragem. 2 Dispositivos de Comando e Controle Todos os equipamentos mencionados na seção anterior requerem um ou mais dispositivos de comando e controle. os CLPs e sensores e atuadores inteligentes).Informática Industrial I DAS/UFSC 2.1.5 Módulos de Controle de Qualidade • sensores e instrumentos de medição • máquinas de medir por coordenadas Estes módulos estão exemplificados na Figura 12. Workstation. comandos eletrônicos analógicos e comandos eletrônicos digitais). Marcelo Ricardo Stemmer 16 . CLP) computadores (PC. comandos eletromecânicos a relés. IC. 2. computador processo) sensores e atuadores inteligentes No presente curso estudaremos os três últimos tipos de dispositivos (computadores tipo PC e sua versão industrial. o IC. Os equipamentos mais importantes são: • • • • • • comandos numéricos computadorizados de máquinas-ferramenta (CNC) controladores de robôs industriais (RC) sistemas de comunicação (LAN) controladores lógicos programáveis (PLC. A maioria dos dispositivos de comando e controle atuais são computadorizados (apesar de que ainda existam comandos mecânicos manuais. Módulos de Processamento e Usinagem.Informática Industrial I DAS/UFSC Figura 6 . Marcelo Ricardo Stemmer 17 . Módulos de Processamento e Usinagem (cont.). Marcelo Ricardo Stemmer 18 .Informática Industrial I DAS/UFSC Figura 7 . Informática Industrial I DAS/UFSC Figura 8 .Módulos de Transporte e Armazenamento Marcelo Ricardo Stemmer 19 . Módulos de Transporte e Armazenamento (cont.Informática Industrial I DAS/UFSC Figura 9 . Marcelo Ricardo Stemmer 20 .). Informática Industrial I DAS/UFSC Figura 10 .Módulos de Manuseio de Materiais e Ferramentas Marcelo Ricardo Stemmer 21 . Módulos de Montagem. Marcelo Ricardo Stemmer 22 .Informática Industrial I DAS/UFSC Figura 11 . Marcelo Ricardo Stemmer 23 .Informática Industrial I DAS/UFSC Figura 12 .Módulos de Controle de Qualidade. . com 64 Kb RAM e 4. 20. 8 ou 12 Mhz e disco rígido de 20 MB. etc.2 Arquitetura do PC A arquitetura básica do PC é mostrada na Figura 13. os computadores do tipo PC (Personal Computer) tem sido cada vez mais utilizados em todos os setores industriais.77 Mhz. com clock já chegando aos 2. baseado no 8088 com 256 KB RAM.Informática Industrial I DAS/UFSC 3 Computadores PC / IC Devido ao aumento crescente da capacidade de processamento. baseado no 80286. serial Controlador de Video Controlador de Disco Outras placas de expansao impressora Mouse Monitor de Video Floppy disc drive Hard disc drive Teclado Figura 13 . seguido rapidamente de novas versões (MMX. com 640 Kb RAM. acompanhada de uma redução drástica de preços. clock de 8 Mhz e disco rígido de 10 MB. Pentium IV). cavacos.BASIC Barramento de dados Clock Processador RAM Interfaces I/O paral. para uso em ambiente industrial.BIOS . Marcelo Ricardo Stemmer 24 . Pentium III. mas são encapsulados para proteção contra umidade. em 1983 foi lançado o PC/XT (“eXtended Technology”). 3. 25 ou 33 Mhz. Barramento de enderecos (EP)ROM .1 Histórico • • • • • • o PC foi introduzido em 1981 pela IBM. em 1992 foi lançado o Pentium. poeira. Pentium II. em 1989 foi lançado o 80486 com co-processador matemático integrado. Os computadores do tipo IC (Industrial Computer) têm a mesma arquitetura básica. em 1984 foi a vez do PC/AT (“Advanced Technology”). Era baseado no 8088 (Intel). óleo. os modelos baseados no 80386 (de 32 bits) foram lançados em 1987 com 16.8GHz. São montados em um “rack” de aço e o monitor e o teclado (usualmente tipo membrana) são encapsulados. frequência de clock de 6.Arquitetura interna do PC. 3. somente 256 endereços ou posições de memória (28) podem ser explicitados. os primeiros dispositivos eram endereçados usando somente 8 bits).O Barramento de Endereços: Antes de enviar ou receber dados de qualquer dispositivo ligado ao barramento de dados.1 Barramento de Dados e Endereços Os barramentos de dados e endereços definem respectivamente o caminho de troca de informações entre o processador e as demais unidades do sistema e o endereço de acesso de cada unidade (Figura 14). Dados Processador Endereços Controle de Endereçamento (Memória ou I/O) Figura 14 . Seguem exemplos da largura dos barramentos de dados de alguns microprocessadores: Processador 8088 (PC/XT) 8086 80286 (PC/AT) 80386.O Barramento de Dados: Para que o processador opere é necessário trocar informações entre os registros internos da CPU e a memória (RAM ou ROM). Um dispositivo pode ser endereçado utilizando toda a largura do barramento de endereços ou somente os 8 bits mais significativos do mesmo (por razões históricas. 80486 Pentium Barramento de Dados 8 bits 16 bits 16 bits 32 bits 64 bits Largura dos Registros da CPU 16 bits 16 bits 16 bits 32 bits 32 bits Um aumento da largura do barramento de dados implica em um aumento da velocidade de troca de informações entre o processador e as memórias e outros dispositivos. com 8 bits.3. o processador tem que selecionar o endereço correspondente deste dispositivo no barramento de endereços.Barramentos no PC.Informática Industrial I DAS/UFSC 3.3 Principais componentes 3. diz-se que o dispositivo é “endereçado como I/O”. . Vale lembrar que. . Seguem exemplos de características dos barramentos de endereços de alguns microprocessadores: Marcelo Ricardo Stemmer 25 . Se toda a largura do barramento de endereços é utilizada. diz-se que o dispositivo é “endereçado como memória”. Se somente 8 bits são usados. bem como acessar outras fontes de informação (dispositivos periféricos). O controlador de interrupções informa a ocorrência de uma interrupção a CPU através de um único sinal (usualmente INTR).576 endereços (1Mbytes) 16 Mbytes 4 Gbytes Segue um exemplo típico de mapa de memória do IBM-PC: Endereço hexadecimal 00000-0007F 00080-003FF 00400-004FF 00500-9FFFF A0000-AFFFF B0000-B7FFF B8000-BFFFF C0000-C5FFF C6000-C7FFF C8000-CBFFF CC000-CFFFF D0000-EFFFF F0000-FFFFF Conteúdo vetores de interrupção BIOS vetores de interrupção livres área de dados da BIOS memória de trabalho do usuário 64 KB reservados vídeo monocromático vídeo cromático vídeo EGA vídeo VGA controlador do disco rígido PC Network reservado 128 KB (expansão ROM) área de programas da BIOS e BASIC residente (ROM) Os barramentos de dados e endereços seguem vários padrões industriais. etc. EIA).12 V : usado em componentes das interfaces externas (serial) e unidades de disco A fonte do PC converte a entrada de 110 / 220 V AC em saídas de +5. Marcelo Ricardo Stemmer 26 . As interrupções geradas por dispositivos externos são controladas por um CI específico. VME. +12 e -12 volts. Sua forma de utilização no PC é ilustrada na Figura 15. definidos pelos fabricantes e por órgãos de padronização (ISO.). toda placa colocada em um slot livre do PC deve ser escolhida de acordo com o barramento em uso.048. sendo 3. Entre eles temos: EISA. Como estes barramentos são diferentes e quase sempre não são compatíveis entre si.3 Controlador de Interrupções Processamento de interrupções é um método de controle e resposta à eventos externos ao computador (dispositivos de I/O. IEC.536 endereços (64Kbytes) 1. etc.3.3. da Intel. VXE. numerados de 0 a 7.2 que: Fonte de alimentação do PC → + 5 V : usado em quase todos os CI’s que operam em nível TTL → + 12 V : usado em alguns CI’s e pelos motores das unidades de disco → . PCI. Um dos chips mais extensamente usados para esta função foi o 8259 PIC (Programmable Interrupt Controller). Ele aceita oito linhas de interrupção. vindas de diferentes periféricos. permitindo o uso de rotinas específicas para cada tipo de interrupção. sendo que a IRQ 0 tem maior prioridade e a IRQ 7 tem menor prioridade (IRQ = Interrupt Request).Informática Industrial I DAS/UFSC Processador 8085 8088 80286 80386 Barramento de endereços 16 bits 20 bits 24 bits 32 bits Capacidade de endereçamento 65. PXI. 3. fornecendo também um código do tipo de interrupção ocorrido. denominado Controlador Programável de Interrupções. definido como endereço 21H de I/O no PC).Serial 1 (Mouse) IRQ5 . 3.Controlador de Interrupções no PC. para marcar a hora de criação de arquivos e a data no PC. as instruções em Assembly a seguir mascaram (desabilitam) a interrupção 6: MOV AL. Por exemplo. 5. 2. sendo que o valor lógico 0 habilita a interrupção e o valor 1 desabilita.Timer IRQ1 . numerados de 0 a 2.3. Cada contador tem uma entrada para um sinal com freqüência de 0 a 2 Mhz.Impressora logica de controle buffer dados Barram. O 8253.AL → → coloca 01000000 em AL habilita todas as interrupções menos a IRQ 6 Se as interrupções no processador principal estão desabilitadas (Interrupt Flag IF = 0). possui 3 contadores independentes.Disco Rigido IRQ6 . por exemplo. A saída é um sinal com freqüência igual a entrada dividida por um número programável de 16 bits. Marcelo Ricardo Stemmer 27 . 4.4 Timer O timer (usualmente um 8253 ou 8254 da Intel) realiza funções de contagem e temporização. a interrupção de maior prioridade é requisitada o 8259 seta o pino INTR no processador principal (por exemplo. O endereço é calculado fazendo “nn” x 4 (uma vez que cada vetor de interrupção ocupa 4 bytes). dados INTA 8288 S0 S1 S2 INTR 8088/8086 Figura 15 . 8088) se as interrupções estão habilitadas (STI).Reservado 08H 09H 0AH 0BH 0CH 0DH 0FH 0EH Vetor de interrupcao 8259 PIC Interrupt mask register In service register Determinacao de prioridades Interrupt request register IRQ3 . Resumo da operação de interrupção: 1. 3.Teclado IRQ2 .40H OUT 21H. Este flag é ajustado com os comandos Assembly STI e CLI. o processador sinaliza INTA (interrupt acknowledge) o 8259 envia o número do vetor de interrupção pelo barramento de dados → “nn” o processador faz um “jump” para a rotina endereçada pelo vetor de interrupções. Certas interrupções podem ser habilitadas ou desabilitadas escrevendo-se uma “máscara de interrupção” no registrador próprio do 8259 (Interrupt Mask Register. sendo que: • a saída 0 é usada como relógio de tempo real. independentemente da máscara de interrupção programada no 8259.Serial 2 IRQ4 . nenhuma interrupção é reconhecida.Disquete IRQ7 .Informática Industrial I DAS/UFSC IRQ0 . muito usado em PCs. a RAM costuma ser subdividida em vários segmentos lógicos endereçados por registros da CPU. transferir dados do controlador de disco para a memória enquanto o processador principal realiza outras operações. sendo usado para transferir dados entre a memória RAM e o controlador de disco e vice-versa. • o canal 2 é usado para leitura de discos e disquetes. Com isto é possível. onde cada célula de memória é composta de Marcelo Ricardo Stemmer 28 .Informática Industrial I DAS/UFSC • a saída 1 é usada para indicar ao controlador de DMA para fazer um “memory refresh” na RAM dinâmica (ver DMA a seguir) • a saída 2 é ligada ao alto-falante para a geração de sons → determinação da freqüência do som. só pode ser lida (a escrita requer um dispositivo especial que não acompanha o PC). possui 4 canais de DMA: • o canal 0 é usado em conjunto com o canal 1 do timer para executar o “memory refresh”.3. 3. Dynamic RAM).5 Controlador de DMA (Direct Memory Access) O DMA (por exemplo. sem requerer com isto a atenção do processador principal. nenhum programa seria retido na memória do PC por mais que alguns milissegundos. que pode ser reescrita sem ser removida do computador. não perde seu conteúdo quando desenergizada) pré-gravada que. No PC. SS para o Stack Segment (segmento de pilha. Por exemplo. projetado para transferir blocos de dados (tipicamente de até 64 Kbytes) de um local ao outro da memória ou entre dispositivos de I/O e a memória. CS para o Code Segment (segmento de código. A maioria dos computadores atuais utiliza a versão de ROM conhecida como EPROM(Erasable Programmable ROM). contendo variáveis locais e parâmetros para subrotinas) e ES para o Extra Segment (segmento extra. 3.3. O simples ato de leitura “refresca” a memória. que também contém dados). que pode ser apagada utilizando luz ultra-violeta e posteriormente reprogramada (tanto o apagamento quanto a escrita requerem um dispositivo especial). Um tipo recente de EEPROM é conhecido como EAPROM (Electrically Alterable Programmable ROM). Nela são armazenadas as variáveis e os programas não permanentes do computador e por isso também é chamada de “memória de trabalho”. Uma versão ainda mais nova de ROM é a EEPROM (Electrically Erasable Programmable ROM). por exemplo. As versões originais da IBM costumavam incluir também a linguagem BASIC em ROM (o que requeria ± 40 Kbytes adicionais de ROM). Nesta categoria se encontra a memória Flash. um 8237) é um processador dedicado.6 Memórias ROM e RAM O PC utiliza dois tipos básicos de memória: • ROM (Read Only Memory): é uma memória não volátil (isto é. • Os canais 1 e 3 usualmente estão livres para outros periféricos. a ROM contém um conjunto de pequenos programas conhecido como BIOS (Basic Input Output System). Para tal. lendo ciclicamente (tipicamente a cada 15 µs) blocos de 64 Kb que. contendo o programa em si). que pode ser apagada com um comando elétrico e reescrita. O chip 8237. • RAM (Random Access Memory): trata-se de uma memória volátil (perde seu conteúdo se faltar energia) que permite tanto a leitura quanto a escrita de dados. Em geral no PC se usa RAM dinâmica (DRAM. durante a operação normal do computador. nos processadores da Intel utilizamos o registro DS para endereçar o Data Segment (segmento de dados. Sem isto. no entanto não são transferidos para lugar algum. contendo variáveis globais). que permite a inicialização do sistema. onde cada célula de memória é constituída de um flip-flop e um transistor. Os chips de memória RAM vem passando por inúmeras inovações tecnológicas.75 ns para a versão SDRAM (Synchronous Dynamic RAM). não requer “refreshment” e é mais rápida (tem tempo de acesso menor). Até bem recentemente. Devido ao principio capacitivo. A SDRAM apresenta um sinal adicional de clock aos sinais de controle. além do teclado. A RAM estática (SRAM. seu uso faz com que a execução dos programas se torne mais rápida. mas é menos usada porque a DRAM requer menos espaço. o alto-falante e. Os computadores atuais utilizam uma pequena área de memória estática SRAM de acesso muito rápido para armazenamento temporário de dados e partes de programas em uso pela ALU (Arithmetic and Logic Unit). número de discos e quantidade de memória • PB (saída): bit 7 = 1 → teclado habilitado bit 6 = 0 → desabilita clock teclado bit 5 = 0 → habilita sinalização de erros de I/O bit 4 = 0 → habilita checagem de erro de memória na RAM bit 3 → define funções da porta PC. entre outros). que permitem acesso mais rápido. a operação de “memory refresh” é realizada periodicamente com auxílio do timer e do DMA). maior capacidade de armazenamento e menor preço. no PC original. parte baixa bit 2 → livre bit 1 → liga e desliga o alto-falante bit 0 → habilita timer Port 2 Marcelo Ricardo Stemmer 29 . 3. conhecidas como “pentes” ou “módulos” de memória. as chaves de configuração do sistema (dip-switches que definiam a quantidade de memória presente.3. as portas PA e PC são configuradas como entradas e a porta PB como saída. caso contrário lê sw1 (dip-switch 1) que indica tipo de vídeo. com tempos de acesso que chegam a 0. Este componente possui 3 portas de 8 bits: • Porta A → Endereço de I/O 60H • Porta B → I/O 61H • Porta C → I/O 62H • Registro de Comando → 63H Na inicialização do sistema. Como o tempo de acesso à memória cache é menor que à memória de trabalho normal. Os chips são montados em pequenas placas de circuito integrado. conhecida como memória “Cache”. a DRAM tem que ser constantemente acessada para manter o conteúdo (como já vimos. Hoje são mais usados os pentes DIMM (Dual In-Line Memory Modules) de 64 e 128 Mbytes.7 Controlador de teclado O chip 8255 é um CI que controla.Informática Industrial I DAS/UFSC um capacitor e um transistor. Static RAM). possui maior capacidade de armazenamento e tem menor custo. com tempo de acesso típico de 60 ns (nanossegundos). os pentes mais usados eram os módulos de memória SIMM (Single In-Line Memory Modules) de 32 e 64 Mbytes. O significado de cada uma das portas é o seguinte: • PA (entrada): contém código de varredura da última tecla pressionada se o bit 7 de PB igual a 1. número de unidades de disco / disquete e tipo de controlador de vídeo presentes. bit 3 = 0. o tipo de vídeo (sw1) O teclado envia os códigos de varredura das teclas pressionadas de forma serial ao PC. bit 3 = 0... Marcelo Ricardo Stemmer 30 . Este buffer pode posteriormente ser lido pelo BIOS ou diretamente pelo programa de aplicação.3.sys). A rotina de tratamento da interrupção da BIOS endereçada pelo vetor 09h da Tabela de Vetores de Interrupção lê o código de varredura da tecla pressionada da porta PA do 8255 e põe o código ASCII correspondente em um buffer. No PC. caso contrário. Uma descrição mais detalhada do tratamento das teclas está na seção 3. PA Dados 8088/86 8 Bits convertidos IRQ1 8259 PIC sinaliza a presença de dados do teclado (INT09H) Figura 16 . Os demais componentes que veremos a seguir não estão montados na placa mãe e são chamados periféricos. senão. Quando um código de varredura é completamente convertido de serial para paralelo (8 bits recebidos). senão indica número de unidades de disco bit 1 → se PB. Todos os componentes vistos até aqui (exceto a fonte de alimentação) estão montados na chamada placa mãe ("mother board"). tem-se um teclado brasileiro e a tabela de conversão em uso é para um teclado americano ou alemão). os programas de aplicação receberão o código ASCII incorreto para as teclas pressionadas.8. Um exemplo de placa mãe é apresentado na Figura 17. indica presença de coprocessador matemático. Esta tabela é usualmente definida na configuração do PC (no caso do DOS. o Registrador de Deslocamento gera uma requisição de interrupção no pino IRQ1 do 8259 (ver controlador de interrupções). Se esta configuração não estiver correta (por exemplo. como ilustrado na Figura 16. os dados seriais são convertidos para paralelo por um Registrador de Deslocamento (tradicionalmente a IBM usava o 74LS322) e repassados a porta PA do 8255. o tipo de vídeo bit 0 → se PB.Controlador de Teclado no PC.Informática Industrial I DAS/UFSC • PC (entrada): bit 7 = 1 → sinaliza erro de paridade na RAM bit 6 = 1 → sinaliza erro de I/O bit 5 = 1 → saída do canal 2 do timer (alto-falante) bit 4 → livre bits 3 e 2 → se PB. indica quantidade de memória. indica loop de teste. através do arquivo config. A conversão de código de varredura para código ASCII é feita segundo uma tabela de varredura do teclado. que sinaliza o evento à CPU. bit 3 = 0. 74LS322 Dados teclado . cada linha de saída do decoder indicado na Figura 18 é levada a zero. a tecla está pressionada. a tecla ALT direita resulta em um código de varredura de 2 bytes. Por exemplo. as teclas que aparecem duplicadas no teclado.3. como a ALT direita e a ALT esquerda. um 8048). a tecla PAUSE (ou BREAK) gera um Marcelo Ricardo Stemmer 31 .8 Teclado O teclado é um dispositivo periférico de comunicação serial para entrada de dados e comandos que possui um microprocessador dedicado (por exemplo.Placa Mãe de um PC/XT. Em cada varredura. E0h+38h. Algumas teclas produzem um código de varredura composto de vários bytes.Informática Industrial I DAS/UFSC Figura 17 . Por exemplo. é enviado 01h e quando ela é solta é enviado 81h. identificar e enviar ao computador o código de varredura da tecla em questão (ver Figura 18). é gerado o código de varredura com 80h adicionado (oitavo bit em 1). se a entrada correspondente do multiplexador estiver também a zero. 3. são distinguidas por este meio. e o 8048 envia serialmente seu código de varredura para o PC (observe que não se trata ainda do código ASCII). em caso positivo. Quando a tecla é solta. encarregado de fazer uma varredura das teclas para verificar se estão pressionadas e. quando a tecla ESC é pressionada. Por exemplo. Certas teclas especiais têm ainda mais bytes em seu código de varredura. Enquanto a tecla ALT esquerda gera o código de varredura 38h. pressionar a tecla Ctrl direita leva o bit 2 do byte 0040:0017h para 1. Marcelo Ricardo Stemmer 32 . A interpretação destes bytes é função do BIOS. Por exemplo. 0=inativo Caps Lock: 1=ativo. a rotina do BIOS ativada pelo vetor de interrupções 09h lê os códigos de varredura enviados pelo teclado byte a byte da porta PA do 8255 e traduz para valores de 2 bytes. as rotinas de serviço do BIOS traduzem os códigos de varredura em informações significativas que um programa de aplicação pode usar. Antes de gerar o código traduzido de 2 bytes para as teclas convencionais. Cada bit destes bytes indica o estado de uma das teclas especiais e é mantido atualizado pelo BIOS. O byte de baixa ordem ou byte principal contém o código ASCII correspondente a tecla pressionada. este bit volta a zero. 5. O mesmo efeito é produzido para as teclas Ins. a tecla PrtSc ativa uma rotina de impressão da tela (ver rotinas da BIOS na seção 3. SCROLL LOCK e PAUSE) é mantida pelo BIOS em dois bytes de status do teclado nas posições de memória RAM 0040:0017h e 0040:0018h.Informática Industrial I DAS/UFSC código de 3 bytes: E1h+1Dh+45h. isto é. pressionando uma vez Caps Lock o bit 6 vai para 1. Desta forma. o BIOS verifica o estado dos bytes de status.2). Desta forma. Todos os demais bits de ambos os bytes indicam o estado momentâneo das teclas correspondentes. A tecla PRTSC (Print Screen) gera 4 bytes: E0h+2Ah+E0h+37h. 6 e 7 do byte 0040:0017h se comportam como chaves.1. mas não mudam quando são soltas. Esta propriedade é útil para vários programas aplicativos (por exemplo.COM do DOS). 0=inativo 1=Alt direito pressionado 1=Ctrl direito pressionado 1=Shift esquerdo pressionado 1=Shift direito pressionado Byte de status 0040:0018h Significado 1=Ins pressionado 1=Caps Lock pressionado 1=Num Lock pressionado 1=Scroll Lock pressionado 1=Pause ativo 1=Sys Req pressionado 1=Alt esquerdo pressionado 1=Ctrl esquerdo pressionado Bit 7 6 5 4 3 2 1 0 Bit 7 6 5 4 3 2 1 0 Os bits 4. Os pares de bytes gerados pelo BIOS são armazenados em um espaço de memória conhecido como buffer do teclado. CTRL+ALT+DEL ativa uma rotina de reinicialização do PC. No windows.4. Por exemplo. que inicia no endereço de RAM 0040:001Eh. A informação de estado destas teclas e de outras teclas especiais (INS. 0=inativo Num Lock: 1=ativo. As teclas de função e as do teclado numérico possuem um zero no byte principal e o código de varredura do teclado no byte auxiliar. Como estes bytes de status estão na memória RAM do PC. o mesmo bit vai para 0. seus valores são invertidos cada vez que as teclas correspondentes são pressionadas. pressionando Caps Lock uma segunda vez. No DOS. 0=inativo Scroll Lock: 1=ativo. enquanto o byte de alta ordem ou byte auxiliar costuma conter o código de varredura em si (ao menos no caso de teclas simples). Ao soltar a tecla. Uma vez recebidos pelo PC. não é necessário manter a tecla Caps Lock pressionada constantemente para gerar letras maiúsculas. SHIFT e ALT) e as teclas de chaveamento (CAPS LOCK e NUM LOCK). editores de texto como o Word e interpretadores de comando como o COMMAND. PrtSc armazena o conteúdo da tela na forma de um bitmap na área de transferência. Num Lock e Scroll Lock. A tarefa de traduzir códigos de varredura é um pouco complicada pela presença de teclas que modificam o significado de um toque: as teclas de shift (CTRL. O significado de cada bit é dado na tabela a seguir: Byte de status 0040:0017h Significado Ins: 1=ativo. Como vimos no item sobre o controlador do teclado. eles podem ser também acessados e alterados por um programa do usuário. Desta forma a tecla z gera um código final no buffer do teclado diferente do obtido com a combinação SHIFT z (que é interpretado como um Z maiúsculo). Algumas teclas ou combinações de teclas ativam diretamente rotinas especiais do BIOS. Informática Industrial I DAS/UFSC Matriz de teclas (23 x 4) +5V .. denominada “CENTRONICS” (nome de um fabricante de impressoras que lançou o padrão).. Multiplexador Figura 18 .. a interface CENTRONICS define uma série de bits de controle. Uma das três portas é usada para dados e as outras 2 portas para controle.3. Para este uso foi definida uma interface padronizada. nivel TTL Dados Placa de interface paralela CS 0 1 . requerem cabos com vários condutores. . A maioria das placas de interface paralela utiliza um 8255 (ver controlador de teclado) como componente central...Teclado do PC 3..3. 3. Marcelo Ricardo Stemmer 33 . 7 controle (10 pinos) 8088/86 Decoder End. Figura 19 .9 Interface Paralela Interfaces paralelas permitem o envio de dados à dispositivos externos à taxas de 8 ou mais bits de cada vez... . A aplicação típica mais usual é o interfaceamento com a impressora. Além de 8 bits de dados. Decoder Codigo de 8048 varredura da tecla pressionada ..10 Interface Serial Pode-se reduzir o número de fios necessários à comunicação com dispositivos externos e com isto reduzir significativamente o custo de fiação utilizando uma interface serial. Para isto. A Figura 19 ilustra a ligação entre o PC e a interface paralela.. que permitem um “Hand-Shake“ entre o PC e a impressora.Interface Paralela. número de start e stop bits (que definem o inicio e o fim de um caracter). o PC sofre uma interrupção (geralmente IRQ 3 ou 4 do 8259) que ativa uma rotina de tratamento do mouse (acessada pelo usuário através do vetor de interrupção 33h). Com o vídeo mapeado como memória. onde é armazenado o conteúdo de cada posição da tela no monitor.. Antes de ser utilizado. como ilustrado na Figura 20. O Mouse é interligado ao PC através de uma interface serial.. interface serial Dados Paralelo comando 8088/86 Decoder .Informática Industrial I DAS/UFSC A conversão interna dos dados de forma paralela (vinda do barramento de dados) para a forma serial é realizada por registradores de deslocamento.Interface Serial. a informação mostrada na tela pode ser alterada na velocidade que o Marcelo Ricardo Stemmer 34 .11 Controlador de vídeo O controlador de vídeo serve de interface entre o PC e o monitor de vídeo. a ser interpretada pelo PC. Vários fabricantes fornecem teclados com este componente. a RS-232-C opera com uma tensão mais elevada que o nível usual TTL (5 volts): -3 a -12V → lógico 1 +3 a +12V → lógico 0 -3 a +3V → indefinido O 8251 seria também adequado para a realização prática da comunicação com o teclado. Ele usualmente é montado em uma placa separada da placa-mãe do PC e inserido em um dos “slots” livres. O 8251 é conectado eletricamente ao mundo exterior pela interface padronizada pela EIA (Electronic Industries Association) RS-232-C. O controlador de vídeo é ligado ao barramento de dados e endereços do PC. que permite o envio de dados serialmente pela linha telefônica. 3. tamanho da palavra (usualmente 7 ou 8 bits) e paridade (para controle de erros de transmissão). Para permitir o envio de sinais a maiores distâncias. dados serie CS End. Esta rotina (mouse-driver) tem que ser carregada na memória na inicialização do PC e fica residente na memória. Figura 20 . Quando dados da interface serial estão disponíveis. A memória de vídeo pode ser acessada tanto pelo controlador de vídeo quanto pelo processador do PC. colocados na placa de controle da interface serial. o 8251 deve ser programado com as características de comunicação desejadas: taxas de transferência (Baud Rate) em bits por segundo. O componente mais utilizado para este fim é a USART (Universal SynchronousAsynchronous Receiver-Transmitter). Cada movimento ou tecla pressionada no mouse é convertido em uma mensagem serial. Outra aplicação típica é o MODEM (Modulator/Demodulator). possuindo memória própria. normalmente um 8251.3. com caracteres de 9 x 14 pixel e gráfico de 720 x 348 pixel) . etc. totalizando 4 Kbytes Dependendo da resolução (número de pontos da tela) e das cores suportadas. não é armazenada a imagem da tela na memória.gráfico (320 x 200. Os códigos ASCII são então traduzidos para imagens na tela por um “gerador de caracteres”. O byte de atributo é representado na Figura 21. Por exemplo. Desta forma.somente para texto → 255 caracteres ASCII .2 modos de operação (texto 80 x 25. No modo texto. 16 cores requerem 4 bits. 640 x 200 com 2 cores de um palete de 16 cores) EGA (Enhanced Graphics Adapter): .Informática Industrial I DAS/UFSC computador escreve dados na memória.). O controlador de vídeo pode operar tanto no modo texto quanto no modo gráfico. sendo que seriam necessários 2 Kbytes para armazenar os códigos ASCII e mais 2 Kbytes para os atributos.texto 80 x 25. O controlador de vídeo lê as posições de memória e envia os comandos correspondentes para o monitor de forma cíclica. um controlador de vídeo tipo CGA operando na resolução de 640 x 200 com um palete de 16 cores requer 64 Kbytes (640 x 200 x 4 / 8). uma vez que vários bits são necessários para representá-las (por exemplo. já que 24=16). Por exemplo. para uma tela com 80 colunas por 25 linhas podemos ter 2000 caracteres (80 x 25). o modo gráfico necessita mais memória. 640 x 350. Red Blue Côr fundo Piscar letras Intensidade Côr frente Figura 21 – Byte de atributo em modo texto. O uso de cores resulta em ainda mais necessidade de memória. Blink Red Green Blue Green Intens. Cada código ASCII ocupa 1 byte de memória. uma resolução gráfica de 640 x 200 pixels com apenas 1 bit por pixel (on/off) utiliza 16 Kbytes (640 x 200 / 8).256 Kbytes RAM Marcelo Ricardo Stemmer 35 . cor.gráfico (320 x 200 com 4 cores. todos com 16 cores de um palete de 64) . No modo gráfico.EGA plus → 640 x 480 . acrescido de um segundo byte que define atributos (piscando.monocromático CGA (Color Graphics Adapter): . 640 x 200. invertido. permitindo assim gráficos de alta velocidade (ao contrário de terminais de vídeo ligados serialmente ao computador). Seguem alguns exemplos históricos de tipos de controladores de vídeo: MDA (Monocrome Display Adapter): .somente cor de fundo + uma cor HGA (Hercules Graphics Adapter): . é armazenado um valor para cada ponto da tela em um ou mais bits. cada caracter 8 x 8 pixel . mas sim apenas o código ASCII (American Standard Code for Information Interchange) para cada caracter representado na tela. A diferença está na forma como os dados são armazenados na memória. O modo texto requer muito menos memória que o modo gráfico.caracteres ocupam matriz 9 x 14 pixel .texto (resolução 80 x 25 com caracteres 8 x 14 e 80 x 43 com caracteres 8 x 8) . texto (80 x 25 e 80 x 43 com caracteres de 9 x 14) .super VGA (800 x 600 e 1024 x 768 com 16 cores exigindo 512 Kbytes RAM) Tipos de monitores de vídeo: Modo de Vídeo MDA CGA EGA ( 640 x 350 ) VGA ( 640 x 480 ) VGA (800x600 e 1024x768) Varredura horizontal 18. Nos computadores mais recentes. A área de memória a ser utilizada é previamente definida pelo processador.Informática Industrial I DAS/UFSC VGA (Virtual Graphics Adapter): .12 Unidades de Disco / Disquete As unidades de disco (rígido ou flexível) se constituem essencialmente de: • disco propriamente dito.gráfico (320 x 200 a 640 x 480 com 256 cores de um palete de 262. inclusive. Em computadores dotados de uma GPU. Marcelo Ricardo Stemmer 36 . que é uma placa com processador e memória próprios e. após o que os dados a salvar ou carregar são transferidos pelo barramento de dados (Figura 22). a placa de vídeo tradicional foi substituída por um novo tipo de periférico conhecido como GPU (Graphic Processing Unit). que controla os motores e converte dados lidos e escritos pelos cabeçotes em informação binária Os dados lidos do disco são colocados pelo controlador de disco direto em RAM.500 MHz Varredura vertical 50 Hz 60 Hz 60 Hz 60 Hz 70 Hz Para permitir a operação do monitor em qualquer um destes modos.3. que monitora automaticamente as freqüências de varredura requeridas pelo controlador de vídeo. área de cache própria. recoberto de material magnético • cabeçotes de leitura / escrita (1 para cada face de cada disco) • motores de passo.800 MHz 31. para girar o disco e posicionar cabeçotes. a CPU não envia mais à placa de vídeo os pixels que compõem desenho a ser apresentado na tela.438 MHz 15. incluindo componentes mecânicos e eletrônicos • controlador de disco / disquete. 3. O controlador de disco tem que ser inicialmente selecionado via barramento de endereços. por meio de um canal DMA.144 cores. exigindo 256 Kbytes RAM) .750 MHz 21. é necessária a utilização de um monitor multissíncrono (“Multisync”). mas sim apenas os parâmetros necessários para realizar um desenho ou animação.500 MHz 31. . por sua vez. de forma que as unidades de disquete têm dois cabeçotes.Informática Industrial I DAS/UFSC Barramento de Endereços Controlador Posiciona cabeçote Seleciona número cabeçote lê/escreve dados Mother board de Disco Barramento de Dados Seleciona Cilindro e trilha Recebe e envia dados Figura 22 .Estrutura de dados de um disco. TRILHA (TRACK) SETOR = 512 Bytes (SECTOR) CILINDRO TRILHA LADO 1 TRILHA LADO 2 CAPACIDADE = Numero de Trilhas x Numero de Setores por trilha x Numero de Cabecotes x 512 Bytes Figura 23 . de forma que as unidades de disco fixo têm vários cabeçotes de leitura / escrita. A capacidade de alguns tipos comuns de discos e disquetes é apresentada abaixo: Tipo de disco disquete 5¼ single disquete 5¼ double Número de cilindros 40 40 Setores por trilha 8 9 Cabeças Capacidade 1 160 Kbytes 2 360 Kbytes 37 Marcelo Ricardo Stemmer . Disquetes atualmente armazenam dados em ambos os lados. Os discos rígidos (“Winchesters”) geralmente consistem de uma pilha de placas que giram unidas. A Figura 23 ilustra a estrutura de um disco e apresenta a fórmula para cálculo da capacidade de armazenamento de dados. são compostas de diversos setores.Controlador de disco.Forma de armazenamento de dados: O disco é subdividido em trilhas concêntricas (“tracks”) que. O disco pode ter informações armazenadas em um único lado (single sided) ou em ambos os lados (double sided). A Figura 24 apresenta a estrutura de uma unidade de disquete. Cada setor pode armazenar 512 Bytes de informação. 6 ms (Fonte: http://www.com/cda/products/discsales/desktop/) • Um HD para Servidores atual. Ultra160 SCSI. Para exemplificar. temos por exemplo: • Um winchester típico de PC Desktop moderno.Informática Industrial I DAS/UFSC disquete 5¼ HD disquete 3½ double disquete 3½ HD disco rígido PC/XT 80 80 80 306 15 9 18 17 2 2 2 4 1. devido a menor velocidade de rotação dos disquetes. 5400 rpm.seagate. 18.2 Mbytes 720 Kbytes 1. como o ST340810A U Series 40810.000 rpm. como o ST318452LC. tem um tempo de acesso médio de 8. tem um tempo de acesso médio de 3. Marcelo Ricardo Stemmer 38 . 15.com/cda/products/discsales/serverdept/) O tempo de acesso de unidades de disquete geralmente é da ordem de 10 vezes maior. Cheetah X15 36LP.44 Mbytes 10 Mbytes O tempo de acesso de uma unidade de disco é definido como o tempo médio requerido para posicionar o cabeçote sobre um dado setor.seagate.9 ms (Fonte: http://www. valores típicos de tempos de acesso encontrados para alguns discos rígidos mais antigos são: Disco do PC/XT → 80 ms Disco do PC/AT → 40 ms Disco do 386 → 28 ms Para efeito de comparação com discos rígidos atuais. Ultra ATA/100.4 GB. 40 GB. Informática Industrial I DAS/UFSC Figura 24 .Unidade de Disquete. Marcelo Ricardo Stemmer 39 . data. como ilustrado na Figura 25..Contém setor de boot (setor 0): comandos para carregar o sistema operacional e. os dados enviados poderão ser escritos em setores adjacentes. Se o processador for rápido. Por exemplo.44MB / 1.Informática Industrial I DAS/UFSC -Fator de “Interleave” (disco rígido): O controlador de disco escreve / lê dados no disco em unidades de 512 bytes (1 setor) de cada vez. caso contrário. produzindo assim um fator de interleave maior que 1. os dados serão escritos pulando um determinado número de setores. tamanho da FAT e número de entradas do diretório raiz FAT (File Allocation Table – Tabela de alocação de arquivos): ..tabela de conteúdo do disco: nome. .Fator de Interleave.. . 2 para AT e 1 para 386 / 486 e todos os PCs mais recentes.tabela com tamanho da área reservada.gerado por FORMAT → número de entradas limitado (1.Estrutura lógica do disco (DOS): A estrutura lógica de um disco rígido ou disquete é definida pelo sistema operacional em uso. winchester → 512 diretórios) Área de arquivos: Marcelo Ricardo Stemmer 40 . . 3 4 5 6 2 1 6 3 2 5 1 8 8 7 7 4 FATOR DE INTERLEAVE = 1 (1 rotacao para ler/escrever 1 trilha) FATOR DE INTERLEAVE = 2 (2 rotacoes para ler/escrever 1 trilha) Figura 25 . todo disco ou disquete formatado pelo DOS é mapeado em quatro áreas distintas: Área reservada Tabela de alocação de arquivos (FAT) Diretório Raiz Área de arquivos (arquivos e subdiretórios) Área reservada: . São valores típicos de interleave: 3 a 6 para XT.. tamanho e local de início de cada entrada no disco .2MB → 224 diretórios.mapa de localização dos setores usados pelos arquivos Diretório Raiz: .Contém registro do formato do disco e. Todo acesso ao hardware deveria ser executado através de funções da BIOS. de forma a garantir a portabilidade dos programas.1. Se o segmento de “boot” não contiver o programa procurado. • BASIC: núcleo da linguagem Basic que é ativado caso o sistema operacional não esteja presente no disco (oferecido no PC da IBM e em alguns compatíveis).4. Para isto. • BIOS (basic Input-Output System): o sistema básico de entrada / saída é um grupo de rotinas em linguagem de máquina que dão suporte à operação do computador.1 Software da ROM O software contido na ROM do PC se compõe essencialmente de 4 elementos: • Rotinas de inicialização: inicializam diversas funções no computador e carregam o sistema operacional. Além de atender as interrupções originadas pelo hardware. carrega o resto do sistema operacional. Para PCs compatíveis. Os endereços de todas as rotinas de serviços do BIOS são armazenados na tabela de vetores de interrupção. o Basic é ativado. Este programa. passa o controle do computador para o programa gravado neste segmento. o BIOS foi concebido para servir de interface entre os programas de alto nível (incluindo programas do usuário e o próprio DOS) e o hardware do PC. B ou C). indicando endereços de rotinas da BIOS verificação de quais equipamentos adicionais estão conectados. o BIOS coloca doze interrupções com serviços acessíveis ao usuário via instrução Assembly INT. 3.Informática Industrial I DAS/UFSC - ocupa maior parte do disco utilizável pelo usuário para arquivos e subdiretórios ( a partir do DOS 2. • extensões da ROM: programas adicionados a ROM principal quando novos equipamentos são adicionados ao computador (opcional) 3.4 Software básico do PC 3.2 BIOS Conceitualmente.4. Resumo dos principais serviços oferecidos pelo BIOS: Marcelo Ricardo Stemmer 41 .4. Todos os serviços da BIOS são chamados por meio de interrupções (de software ou hardware). por sua vez. Estes serviços estão descritos na tabela a seguir. uma mensagem de erro é apresentada ao invés disto.0) 3. com eventual chamada das extensões da ROM para a inicialização destes • carregamento do sistema operacional do disco (unidade A.1 • • • • Rotinas de Inicialização As rotinas de inicialização executam as seguintes tarefas: teste de confiabilidade do computador para assegurar que tudo esta funcionando corretamente inicialização dos circuitos e equipamentos padrão ligados ao PC definição da tabela de vetores de interrupção. a rotina tem que ler segmentos de “boot” do disco e se tiver sucesso.1. Este último já é padrão no universo das estações de trabalho ("Workstations"). o OS/2 (IBM) e o UNIX (particularmente versão GNU/LINUX). da Microsoft. Interrupt Vector Serviços oferecidos pelo DOS 42 Marcelo Ricardo Stemmer . IBMDOS.COM (versão IBM) ou MSDOS.4. é ativado pela rotina de inicialização da BIOS e carrega o DOS propriamente dito na RAM (3 outras partes ficam residentes na memória).SYS (versão Microsoft): contém as rotinas de serviços do DOS.) PRINTER-I/O: serviços de impressora (inicializa. a Digital Research também oferece sua versão do DOS. carregando o DOS TIME AND DATE: serviços de hora e data ( lê e acerta hora e data) 3. envia dados. tipo e posição do cursor. da Microsoft. O DOS compõe-se de 4 partes principais: • • • • Boot Strap Loader: residente no setor lógico 0. ambas as empresas passaram a fornecer seus próprios produtos: o MS-DOS. rolar página de vídeo. etc. Estas extensões podem se mudanças ou adições básicas de I/O.COM (versão IBM) ou IO.COM: interpretador de comandos do DOS.) → no IBM.) BASIC: ativa o Basic da ROM (no IBM) BOOT STRAP LOADER: lê setor de “boot”. lê dip-switches via 8255 MEMORY SIZE DETERMINATION: para determinar a quantidade de memória instalada DISQUETE. não aparece com o comando DIR. interfaces. Posteriormente. etc. Além disto. assim como os da BIOS podem ser chamados por um grupo de interrupções.SYS (versão Microsoft): contém extensões do ROM-BIOS. write. coprocessador. o Windows-NT (New Technology. IBMBIO. denominada DR-DOS. mostrar caracter ASCII no vídeo. Ainda se discute que sistema operacional deverá herdar o imenso mercado dos PCs no futuro próximo. controlador de vídeo. Os candidatos mais fortes no momento são o Windows 95/98 (Microsoft) e seu sucessor Windows-ME. conforme a tabela a seguir. etc. → arquivo escondido. etc. lê e escreve) CASSETE-I/O: serviços de fita cassete (não mais usados) KEYBOARD-I/O: serviços do teclado (aguarda digitação tecla. Compara o que foi digitado com nomes dos comandos internos ou procura no disco um programa com nome correspondente. e o PC-DOS. acender e definir cor de pontos. format. O produto mais difundido sempre foi o MS-DOS. selecionar página de vídeo. da IBM. rotinas para tratar novos dispositivos periféricos.) EQUIPMENT DETERMINATION: permite determinar quais periféricos opcionais estão conectados ao sistema (impressoras. status. unidades de disco. etc. COMMAND. lê status.I/O: rotinas de interface com controlador de discos (read. Estes serviços.Informática Industrial I DAS/UFSC Interrupt Vector INT 05H INT 10H INT 11H INT 12H INT 13H INT 14H INT 15H INT 16H INT 17H INT 18H INT 19H INT 1AH Serviço PRINT SCREEN: imprime o conteúdo da tela VIDEO-I/O: rotinas de interface com o controlador de vídeo (modo de operação.2 O Sistema Operacional DOS (Disk Operating System) O sistema operacional DOS foi originalmente concebido para os computadores IBM-PC em um trabalho conjunto da IBM e da Microsoft. com núcleo semelhante ao MVS/DEC) e seu sucessor Windows-2000.) RS232C-I/O: serviços de comunicação via interface serial (inicializa. etc. Seguem exemplos de alguns comandos mais usuais do DOS: Comando HELP DIR MD RD CD DEL. 75 funções disponíveis) Endereço de término de programa (uso interno do DOS) Endereço do manipulador de CTRL-C (uso interno do DOS) Endereço do manipulador de erro crítico (uso interno do DOS) Leitura absoluta do disco Escrita absoluta do disco Termina programa e mantém residente (TSR = Terminate and Stay Resident) Acesso à programas residentes (interrupção multiplexadora) Interrupção Ociosa (sem ação.1 Marcelo Ricardo Stemmer 43 . UNDELETE REN COPY. • AUTOEXEC.25.Muda o diretório corrente DELete .COM Ajusta denominação para disco Mostra denominação do disco Chama editor padrão do DOS Ajuste de modo de vídeo.93 PATH C:\DOS LABEL A:TESTE VOL A: EDIT A:P1. XCOPY TYPE FORMAT CHKDSK MEM VER TIME DATE PATH LABEL VOL EDIT MODE Função no DOS Ajuda On-line para comandos DOS Lista conteúdo de um diretório Make Directory .TXT B:T2.deleta um arquivo UNDELETE .Remove diretório. caso vazio Change Directory .Informática Industrial I DAS/UFSC INT 20H INT 21H INT 22H INT 23H INT 24H INT 25H INT 26H INT 27H INT 2FH INT 28H Término de programa (retorno ao DOS) Chamada de serviços gerais do DOS (aprox.BAT: série de comandos do DOS desejados pelo usuário na inicialização.TXT TYPE T2.Renomeia arquivo Copia conteúdo de um arquivo de um disco para outro.Cria diretório abaixo do corrente Remove Directory .checa conteúdo e trilhas de um disco para identificar problemas MEMory .TXT REN A. o programa carregador executa comandos contidos nos arquivos: • CONFIG.DOC FORMAT A:/4 CHKDSK C:/F MEM /C VER TIME 10:25:15 DATE 10. de um diretório para outro ou para um arquivo com outro nome Lista na tela conteúdo de um arquivo (ASCII) Formata disco ou disquete CHecK DiSK .TXT UNDELETE A1.8. interface serial e outros Exemplo de uso HELP DEL DIR /AD MD TEMP RD TEMP CD TEMP DEL *.Indica conteúdo da memória de trabalho (RAM) VERsion .ASM MODE COM1:96.SYS: carrega drivers de dispositivos.Mostra versão do DOS Ajuste e leitura da hora Ajuste e leitura da data Ajusta trilha de procura de arquivos para COMMAND.DOC B.DOC COPY A:T1.recupera arquivo REName .E.COM. ativada enquanto nenhuma tecla é pressionada) Antes de passar o comando do computador ao COMMAND. A maneira de se comunicar com um computador chama-se programa e a única linguagem que o computador entende chama-se linguagem de máquina. Se não houver erros. foram implementados nos anos 50 os primeiros programas para a tradução de linguagens semelhantes à humana (linguagens de "alto nível") em linguagem de máquina. Ex. converte-a para a linguagem de máquina para finalmente executá-la. CPG-EEL. a inteligência dos sistemas automatizados é implementada através de programas computacionais. Além disto. se não houver erro. em 2000/1 44 Marcelo Ricardo Stemmer .OBJ com as instruções já traduzidas. tolerância a falhas ou comportamento determinístico com restrições temporais (sistemas temporeal).1 Introdução Atualmente. • Compiladores : Traduzem o programa inteiro em linguagem de máquina antes de serem executados. a programação destes sistemas se faz de suma importância. configurá-lo e acima de tudo programá-lo para que este execute a tarefa de automatização atendendo requisitos industrias. emprega-se cada vez mais sistemas computacionais na automatização de processos industriais. para permitir uma maior flexibilidade e portabilidade no desenvolvimento de software. Entretanto.Informática Industrial I DAS/UFSC 4 Programação do PC e de sistemas computadorizados* 4. o desenvolvimento em hardware permitiu que. cria um produto final em disco usualmente com sufixo . um dos grandes paradigmas tecnológicos hoje é o desenvolvimento de programas para a realização de tarefas complexas e que exigem um alto grau de inteligência. então. este profissional deve conseguir instalar o sistema. faz uma verificação de consistência de sua sintaxe e. C. para a próxima instrução. Este programa não pode ser executado até que sejam agregadas a ele rotinas em linguagem de máquina que lhe permitirão a sua execução. a evolução em software não se deu na mesma velocidade que a de hardware. C++. mas os programas são mais rápidos (na ordem de 100 vezes ou mais). Além da maior velocidade. mas são lentos. Portanto todos os programas que se comunicam com a máquina devem estar em linguagem de máquina. que. Oferecem em geral menos facilidades de depuração que interpretadores. Compiladores bem otimizados produzem código de máquina quase tão eficiente quanto aquele gerado por um programador que trabalhe direto em Assembly. FORTRAN. o compilador gera um programa em disco com o sufixo . Ex. Segue. PASCAL.OBJ.2. repetindo o processo até que a última instrução seja executada ou a verificação de consistência aponte algum erro.: BASIC Interpretado.: BASIC Compilado. MÓDULA . Entretanto. etc. Java. Basicamente. além de juntar eventuais bibliotecas e módulos necessários ao programa . os processos industrias sejam automatizados e interligados através de sistemas computacionais. Um engenheiro que atua nesta área deve conhecer os sistemas computacionais disponíveis e ser capaz de selecionar o melhor equipamento para uma dada aplicação.EXE (isto depende do sistema operacional em uso) que pode ser executado diretamente a partir do sistema operacional. cada vez mais. outras vantagens dos compiladores podem ser mencionadas: * capítulo atualizado com auxílio do estagiário de docência Alexandre Orth. como confiabilidade. Desta forma. Nas últimas décadas. comandando os componentes de hardware para executar a tarefa com o comportamento desejado. “linkeditor” ou simplesmente “linker”. Neste contexto. São muito bons para a função de depuração ("debugging") de programas. Os referidos programas de tradução para a linguagem de máquina podem ser classificados em duas categorias: • Interpretadores: Um interpretador lê a primeira instrução do programa. Este trabalho é feito por um programa chamado “editor de ligações”. O aluno deve buscar formar uma boa “base” antes de se preocupar com as estruturas mais complexas. Turbo Pascal for Windows.2. A linguagem "C" se originou das linguagens BCPL e B desenvolvidas em 1970. Isto implica na grande portabilidade de “C”. 4. um programador C é capaz de desenvolver programas tão eficientes. concentração e organização.: UNIX. A linguagem “C” foi utilizada para portar o UNIX para outros computadores. A linguagem "C" possui uma característica dual: • é considerada linguagem estruturada de alto nível e.Informática Industrial I DAS/UFSC • • é desnecessária a presença do interpretador ou do compilador para executar o programa já compilado e linkeditado. i. pela padronização dos compiladores existentes (através da norma ANSI C) e flexível...1 Histórico de C O compilador "C" vem se tornado o mais difundido em ambiente industrial. pequenos e velozes quanto os programas desenvolvidos em Assembly. haja visto que basta a implementação deste núcleo básico para um dado processador e automaticamente já estará disponível um compilador “C” para este processador. A linguagem “C” é baseada em um núcleo pequeno de funções e estruturas básicas. portável. o aluno deve prosseguir neste aprendizado no seu ritmo. inicie por datilografar o seu código com o auxílio de um processador de textos em modo ASCII. interpretadores.EXE não podem ser alterados. etc. todo programa é desenvolvido a partir deste núcleo básico. A linguagem de programação “C” tornou-se rapidamente uma das mais importantes e populares. Os programas em “C” tendem a ser bastante compactos e de execução rápida. próxima da linguagem de máquina. existem compiladores “C” para a grande parte dos sistemas computacionais atualmente disponíveis.2 Conceitos Básicos da Programação em C 4. Ritchie e Ken Thompson no início da década de 70. processadores de texto e mesmo sistemas operacionais (ex. Grave o programa em disco dando a ele um nome como sufixo . Desta forma. com calma e segurança. a linguagem “C++”.2. 4. A linguagem “C” vem sendo usada para desenvolver muitas aplicações como compiladores. diz-se que C é também uma linguagem de baixo nível.C. Por isso. e rodava em um DEC PDP11 (Digital Equipment Corporation). Devido também a este pequeno núcleo.). especificamente por Dennis M. O programa assim gerado é chamado de código fonte.. Por esta razão. Marcelo Ricardo Stemmer 45 . programas . A caminhada é feita passo à passo. que permite escrever programas muito próximos à linguagem de máquina. o que protege o código-fonte. A primeira versão de "C" foi implementada para o sistema operacional UNIX pela Bell Laboratories. Estudaremos aqui uma das linguagens de alto nível mais utilizadas na indústria: a linguagem "C". permitindo-se consolidar os conhecimentos através dos exemplos e exercícios. • "Assembly" de alto nível. A programação é uma atividade que requer paciência. O aprendizado desta técnica deve acontecer de forma gradual para que o programador entenda bem os conceitos envolvidos e compreenda os diversos mecanismos disponíveis. MS-DOS.2 Criando um Programa Executável Para criar um programa em “C”. resultado da introdução da programação “Orientada a Objetos” à linguagem “C”. principalmente por ser muito poderosa.e. e posteriormente a sua sucessora. Por isso. } < outras funções > Vamos começar por um programa bem simples em C.Ilustração do processo de criação de um programa em C.Exe linkar Arq3. Por fim. o que criará. um programa com sufixo . compile o código fonte seguindo as instruções do seu compilador. main() { < declarações locais >. no caso dos sistemas operacionais DOS e Windows. /* Programa : Bom Dia! */ #include <stdio.C Arq1. } Na primeira linha. Isto permite que Marcelo Ricardo Stemmer 46 . basta linkeditar o objeto seguindo as instruções do seu linkeditor. Você pode escrever este programa em um arquivo ASCI e salvá-lo com um nome terminando em “. O programa gerado é chamado de executável.Obj CPU Figura 26 .Obj MyProgram. É muito importante que os programas sejam comentados de forma organizada.2. os símbolos /* e */ servem para delimitar um comentário do programa.Informática Industrial I DAS/UFSC Na seqüência. /∗ comentário ∗/ < instruções >. compilar linkar Programa: "Olá Mamãe!!!" Arq1. 4.EXE em disco. O programa serve para escrever na tela a frase “Bom Dia!!!!”.OBJ em disco.C” . O programa gerado é chamado de objeto. o que criará um programa com o sufixo . A Figura 26 apresenta o processo de geração de um programa em C.3 A Estrutura Básica de um Programa em C A forma geral de um programa em "C" é a seguinte: < diretivas do pré-processador > < declarações globais >.Obj ABC linkar Arq2.h> void main() { printf(“Bom Dia!!!!”). esta função deve ser única. segue-se com uma diretiva para o pré-processador “#include <stdio. Esta instrução é uma chamada à função printf(). entrada e saída padrão) e irá linká-la posteriormente ao programa. Todas as instruções de programa tem que ser declaradas dentro de alguma função (na main() ou outra qualquer). No caso deste programa exemplo. Portanto. As funções e as suas características serão apresentadas em detalhes nos próximos capítulos. Como este é o valor retornado pela função main(). A final de cada instrução em C. Ela é necessária em nosso exemplo. temos a função “main()”. Por fim. Marcelo Ricardo Stemmer 47 . aparecendo somente uma vez em cada programa. Variáveis declaradas no início do arquivo fonte são consideradas “globais”. Printf é uma função definida em “stdio. As instruções C são sempre encerradas por um ponto-e-vírgula (. Você pode colocar espaços. isto significaria que a função main() deveria retornar um valor do tipo inteiro ao final de sua execução. Esta função indica ao compilador em que instrução deve ser começada a execução do programa. pois usamos a função printf. facilitando o seu entendimento e manutenção. int main() { printf(“Bom Dia!!!!”). pois o compilador ignora estes caracteres. Nota-se que a função é chamada escrevendo-se o nome desta e colocando-se os parâmetros desta entre parênteses. Estas chaves definem o bloco de instruções a serem executados por esta função. Ao escrever esta linha de código. O ponto-e-vírgula é parte da instrução e não um simples separador. Isto fica explícito através da palavra-chave void (inglês para vazio) escrita na frente do programa. return 0. Isto advém do fato de C ter um núcleo pequeno de funções básicas. A primeira instrução dada dentro do programa é “printf(“Bom Dia!!!!”). pois isto melhora muito a legibilidade do programa. faz-se necessário o acréscimo de um pontoe-vírgula. O programa termina quando for encerrada a execução da função main(). caracteres de tabulação e pular linhas à vontade em seu programa. Em C não há um estilo obrigatório.e. ela não recebe nenhum parâmetro e também não retorna parâmetro nenhum. Depois. isto é. Se em vez de void tivéssemos escrito int. procure manter os programas tão organizados quanto for possível. o pré-processador irá acrescentar ao programa todas as funcionalidades definidas na biblioteca “stdio” (Standard Input Output.”.h>”. isto é.). são visíveis (i. As variáveis em C podem estar dentro de uma função ou no início do arquivo fonte. visíveis somente pela função onde são declaradas. Entretanto. Variáveis declaradas dentro de uma função são consideradas “locais”. servindo apenas para a documentação e esclarecimento do programador. este também será o valor retornado pelo programa após a sua execução. os parênteses nos certificam disso e o ponto-e-vírgula indica que esta é uma instrução. você poderá usufruir de todos os serviços disponíveis nesta biblioteca.h” para escrever dados na janela console. acessíveis) para todas as funções do programa. que requer esta biblioteca. Todas as instruções devem estar dentro das chaves que iniciam e terminam a função e são executadas na ordem em que as escrevemos.Informática Industrial I DAS/UFSC outras pessoas possam facilmente entender o código fonte. /* indica ao OS que não ocorreu nenhum erro durante a execução do programa */ } Todo o corpo de uma função em C é inicializado e finalizado através das chaves { e }. Desta forma. "C" distingue nomes de variáveis e funções em maiúsculas de nomes em minúsculas. Os comentários não são interpretados pelo compilador. int. A segunda instrução. j ou k são automaticamente consideradas inteiros pelo compilador). todas as variáveis devem ser explicitamente declaradas (Isto não é o caso de todas as linguagens. que são: Identificador char int float double void Categoria Caracter Inteiro Real de ponto flutuante Real de ponto flutuante de dupla precisão Sem valor (vazio). O emprego da função printf() será apresentado em detalhe posteriormente. A terceira instrução chama a função printf() mandando o nome da variável como argumento. é um exemplo de declaração de variável. os tipos de dados básicos podem estar acompanhados por “modificadores” na declaração de variáveis. isto é.2. poderá declará-las de uma única vez separando seus nomes por vírgulas. Uma variável em C é um espaço de memória reservado para armazenar um certo tipo de dado e tendo um nome para referenciar o seu conteúdo. compondo assim a frase apresentada na tela. foguete. atribui um valor à variável num e este valor será acessado através de seu nome. variáveis que começam com i. por exemplo. Usamos o operador de atribuição (=) para este fim. num = 2.h> void main() { int num. apresenta um tipo. helicoptero. valores diferentes. } /* declaração */ /* atribui um valor */ /* acessa a variável */ A primeira instrução. num = 2.2. num. printf(“Este é o número dois: %d”. Em Fortran. uma variável é um espaço de memória que pode conter. int num. Em C existem apenas 5 tipos básicos de variáveis. que esta irá ocupar e a forma como o seu conteúdo será armazenado. O espaço de memória de uma variável pode ser compartilhado por diferentes valores segundo certas circunstâncias. a cada tempo. Se você tiver mais de uma variável do mesmo tipo.Informática Industrial I DAS/UFSC 4. e um nome. num). Em C. /* Programa : Exemplo de variáveis! */ #include <stdio. Os “modificadores” de tipos oferecidos em C são: Marcelo Ricardo Stemmer 48 . Esta lê o valor da variável e substitui na posição indicada por %d. em bytes.5 Tipos de Dados O tipo de uma variável informa a quantidade de memória. Com exceção de void. Em outras palavras.4 Variáveis As variáveis são o aspecto fundamental de qualquer linguagem de computador. 4. int aviao. 483. isto é. O tipo int tem sempre o tamanho da palavra da máquina. Tabela de Palavras Chave em C: auto default float break do for case double goto char else if const enum int continue extern long register return short signed sizeof static struct switch typedef union unsigned void volatile while Segue um exemplo de programa que emprega as variáveis apresentadas. double x = 3.967. letras minúsculas e maiúsculas são diferentes. } Marcelo Ricardo Stemmer /∗ /∗ /∗ /∗ /∗ /∗ variável variável variável variável variável converte Real não inicializada Inteira não inicializada Double inicializada com ‘3.147.768 a +32.294.535 -2.7E-308 a ±1.767 0 a 65.647 0 a 4.7E+308 ±1. indicam que estas declarações são optativas.295 ±3.24’ Char inicializada com ‘a’ ‘i’ recebe o valor 100 tipos ∗/ ∗/ ∗/ ∗/ ∗/ ∗/ 49 . i = 100. void main() { float y. em computadores de 16 bits ele terá 16 bits de tamanho.4E-38 a ±3. Emprega-se o complemento de dois dos números positivos para o cálculo e representação dos números negativos. Em C. char c = 'a'.7E-308 a ±1.Informática Industrial I DAS/UFSC Modificadores signed unsigned long short Efeito Bit mais significante é usado como sinal Bit mais significante é parte do número (só +) Estende precisão Reduz precisão A associação entre identificadores e modificadores resulta nos seguintes tipos de dados: Tipo (signed) char unsigned char (short) (signed) int (short) unsigned int (signed) long int unsigned long int float long float double Tamanho 1 Byte 1 Byte 2 Bytes 2 Bytes 4 Bytes 4 Bytes 4 Bytes 8 Bytes 8 Bytes Valores possíveis -128 a +127 0 a 255 -32.4E+38 ±1.648 a +.24.. A escolha de nomes significativos para suas variáveis pode ajudá-lo a entender o que o programa faz e prevenir erros. Por exemplo “short unsigned int” indica a mesma precisão que “unsigned int”. Uma variável não pode ter o mesmo nome de uma palavra-chave de C (nomes reservados). int i. y = (float) i.7E+308 Observação: As declarações que aparecem na tabela acima entre parênteses (). 6 Constantes Um constante tem valor fixo e inalterável. se você converter um float num int. Suponha que você tenha uma variável ‘x’ de tipo A e queira converte-la para o tipo B e armazená-la em y deste tipo. No primeiro programa exemplo.”.81. const int size = 400. tem valor sobre todo o código). Marcelo Ricardo Stemmer 50 . int x = 0.Informática Industrial I DAS/UFSC Preste atenção na operação “y= (float) i. /* Equivalente à: } x = 3. Uma constante assim declarada só pode aparecer do lado direito de qualquer equação (isto eqüivale a dizer que não pode ser atribuído um novo valor àquela “variável” durante a execução do programa). Você pode executar esta operação através da operador: y = ((B) x). Há duas maneiras de declarar constantes em C: a) usando a diretiva #define do pré-processador: # define < nome da constante > < valor > Esta diretiva faz com que toda aparição do nome da constante no código seja substituída antes da compilação pelo valor atribuído.1415. Não é reservado espaço de memória no momento da declaração define. Você pode perder informações importantes por causa desta conversão. Exemplo: const char letra = 'a'." nem "=" */ b) utilizando a palavra-chave "const": const < tipo > < nome > = < valor >. você perderá todos os dígitos depois da vírgula (precisão).2. Por exemplo. Atenção: Cuidado ao converter variáveis com precisão grande para variáveis com precisão pequena. A diretiva deve ser colocada no inicio do arquivo e tem valor global (isto é. Esta forma reserva espaço de memória para uma variável do tipo declarado. Exemplo: #define size 400 #define true 1 #define false 0 /* → não usa ". const double gravidade = 9. void main() { float y = 3. ou seja. */ 4. x = (int) y. Esta operação é muito empregada para conversão de tipos de variáveis diferentes. mostramos o uso de uma cadeia de caracteres constante juntamente com a função printf(): printf(“Bom Dia!!!!”). variáveis que utilizam um número diferente de bits para representar dados. o endereço age como intermediário entre a variável e o programa que a acessa. /* atribui ao ptr o endereço da variável num num = 10. O endereço de uma variável pode ser passado à um ponteiro através do operador &. uma constante tipo cadeia de caracteres entre aspa duplas e constantes numéricas com o número propriamente dito. utilizase o endereço de memória de uma variável para acessá-la. Dizemos que uma variável aponta para uma outra quando a primeira contém o endereço da segunda.Informática Industrial I DAS/UFSC /* Programa: Exemplo do uso de Constantes */ #define Size 4 void main() { const char c = ’c’. Além disto. const int num = 10. A declaração de ponteiros tem um sentindo diferente da de uma variável simples. isto é. Este endereço é a localização de uma outra variável na memória. px contém o endereço de uma variável do tipo int. Portanto. valor.2. a declaração motiva o compilador a reservar dois bytes de memória onde os endereços serão armazenados. O mecanismo usado para isto é o endereço da variável. Um ponteiro tem como conteúdo um endereço de memória. Para cada nome de variável (neste caso px). /* declara as variável inteira ‘num’ e ‘valor’ int *ptr. A instrução: int *px. inteiro). Basicamente. um ponteiro é uma representação simbólica de um endereço. como apresentado abaixo: /* Exemplo com Ponteiros */ void main() { int num. o compilador deve estar ciente do tipo de variável armazenada naquele endereço (neste caso. /* inicializa o ponteiro com o endereço ‘0’ ptr = &num. /* declara um ponteiro para um inteiro ptr = 0. } Em C uma constante tipo caracter (char) é escrita entre aspas simples. De fato. /* atribui a variável inteira o valor ‘10’ valor = *ptr. Um ponteiro proporciona um modo de acesso a variáveis sem referenciá-las diretamente. int val = Size.141523 4. declara que *px é um dado do tipo int e que px é um ponteiro. Exemplos de constantes: a) caracter: ‘a’ b) cadeia de caracteres: “Bom Dia !!!!” c) número: -3.7 Ponteiros Uma das mais poderosas características oferecidas pela linguagem C é o uso de ponteiros. /* acessa o conteúdo apontado por ‘ptr’ e /* atribui a ‘valor’ } */ */ */ */ */ */ */ Marcelo Ricardo Stemmer 51 . onde o conteúdo apontado por ‘ptr’ é acessado e copiado para a variável ‘valor’. declara-se um ponteiro para uma variável do tipo inteira. apresentaremos as funcionalidades dos ponteiros a medida que formos evoluindo no aprendizado de C. Que contenha pelo menos a declaração de um ponteiro. Utilize as diretivas #define para criar constantes e empregue estas constantes para inicializar as variáveis do programa acima. World!” ou “Olá. Crie um programa que exemplifique a utilização de ponteiros. Estamos aqui apresentando os ponteiros primeiramente como um tipo de dado especial. Analise o seguinte programa: /* Testando 1.5.3 */ #define Default_Y 2 52 Marcelo Ricardo Stemmer . /* j recebe o valor ‘2’ */ ptr = &i. 4. j.Informática Industrial I DAS/UFSC Neste programa. 2. isto indicará que este endereço contém uma valor inválido e. 2. a obtenção do endereço de uma variável com o operador ‘&’ e o acesso ao dado representado pelo ponteiro. Use o método para a conversão de tipos para converter: a) A variável do tipo char em todos os outros tipos de variáveis. muito empregado para evitar o aparecimento de erros. /* cria as variáveis */ i = 1. Discuta o que acontece com a precisão das variáveis. Inicialize estas variáveis com valores típicos. Como ‘ptr’ contém o endereço de ‘num’. Logo após. 2. O importante aqui é entender o conteúdo de um ponteiro e como este pode ser empregado. logo ‘ptr’ poderá já acessar o valor 10 armazenado na variável ‘num’. enquanto o endereço de um ponteiro for nulo. Este é um procedimento normal na manipulação de ponteiros. emprega-se o operador & para obter o endereço da variável ‘num’ e armazenar este endereço em ‘ptr’. /* ptr recebe o valor do endereço de i */ *ptr = *ptr + j.2. sua inicialização com zero. Posteriormente. Na seqüência.2. atribuímos a variável inteira ‘num’ o valor 10. Este ponteiro tem o seu conteúdo inicializado com ‘0’.8 Exercícios 2. /* eqüivale à: i = i + j */ } Nosso objetivo neste momento não é apresentar todas as potencialidades dos ponteiros. Isto é feito na última linha. Em seguida. portanto. b) A variável do tipo double em todos os outros tipos de variáveis.2.3. *ptr. 2. Crie o seu programa “Hello. o conteúdo representado por este endereço não deve ser acessado.4. /* i recebe o valor ‘1’ */ j = 2.1. Crie um programa que contenha todos os tipos de variáveis possíveis e as combinações dos modificadores possíveis. Mamãe!”. pois. Outro exemplo da manipulação de ponteiros: void main() { int i. primeiro declaramos duas variáveis inteiras. Ela não faz parte da definição de C mas todos os sistemas têm uma versão de printf() implementada. Cada argumento deve ser separado por uma vírgula.h> Marcelo Ricardo Stemmer 53 . 4. printf(“Este é o número dois: %d”. por isso. A função printf()pode ter um ou vários argumentos.h" (Standard Input Output) e "conio. No nosso segundo exemplo. estas bibliotecas devem ser incluídas nos programas aplicativos através da diretiva ‘include’: #include <stdio. No primeiro exemplo. colocamos um único argumento: “Bom Dia !!!!”.3. o código de formatação %d solicita a printf() para imprimir o segundo argumento em formato decimal na posição do string onde aparece o %d. Ela permite a saída formatada na tela. O próximo exemplo mostra o uso do código %s para imprimir uma cadeia de caracteres: /* Exemplo da função Printf() */ #include <stdio. const int *ptr = 0. *ptr = *ptr + y. printf()aceita vários outros.h> Algumas das funções de entrada e saída para a console mais utilizadas são apresentadas a seguir: 4.3 Entrada/Saída do Console As rotinas de entrada/saída do console se encontram nas bibliotecas "stdio. Já vimos duas aplicações diferentes da função printf(): printf(“Bom Dia!!!!”). Além do código de formatação decimal (%d).1 Printf() A função printf()é uma das funções de E/S (entrada e saída) que podem ser usadas em C. O string de formatação pode conter caracteres que serão exibidos na tela e códigos de formatação que indicam o formato em que os argumento devem ser impressos. } Aponte onde está o erro e explique porque. colocamos dois: “Este é o número dois: %d” .h" (Console Input Output) e. e a variável num a direita da vírgula que separa os argumentos. No segundo entretanto.h> #include <conio. < lista de parâmetros >). num). A sintaxe geral de printf()é a seguinte: printf(“string de formatação“. ptr = &num. int y = Default_Y.Informática Industrial I DAS/UFSC void main() { const int num = 10. que está à esquerda. Por exemplo. Aqui. \n representa a mudança de linha. O \n é um código especial que informa a printf() que o restante da impressão deve ser feito em uma nova linha.”. A string de formatação define a forma como os parâmetros serão apresentados e tem os seguintes campos: "%[Flags] [largura] [. além do código de formatação.precisão] [FNlh] < tipo > [\Escape Sequence]" onde: Flags + em branco # Efeito justifica saída a esquerda apresenta sinal (+ ou -) do valor da variável apresenta branco se valor positivo. apresentar como "Far" => base : offset (xxxx : xxxx) N = em ponteiros.se valor negativo apresenta zero no início p/ octais apresenta Ox para hexadecimais apresenta ponto decimal para reais largura = número máximo de caracteres a mostrar precisão = número de casas após a vírgula a mostrar F = em ponteiros. na verdade. chamado de nova-linha (equivalente ao pressionamento da tecla ‘Enter’ em um editor de texto). Os caracteres que não podem ser obtidos diretamente do teclado para dentro do programa (como a mudança de linha) são escritos em C. } A saída será: Venus esta a 67 milhoes de milhas do sol. A combinação de caracteres \n representa. 67). sinal de .Informática Industrial I DAS/UFSC void main() { printf(“%s esta a %d milhoes de milhas \n do sol. como a combinação do sinal \ (barra invertida) com outros caracteres. apresentar como "Near" => offset h = apresentar como "short" l = apresentar como "long" Escape Sequence \\ \” \0 \a \b \f \n \o \r \t \x Efeito Barra Aspas Nulo Tocar Sino (Bell) Backspace – Retrocesso Salta Página de Formulário Nova Linha Valor em Octal Retorno do Cursor Tabulação Valor em hexadecimal Marcelo Ricardo Stemmer 54 . a expressão de controle de printf() contém um conjunto de caracteres estranho: \n. um único caractere em C. “Venus”. 3f\n".%ld %lf %o %p %s %u %x Formato Caracter Inteiro decimal (signed int) Formato científico Real (float) Decimal longo Real longo (double) Octal (unsigned int) Pointer xxxx (offset) se Near. x = 3. /* pula linha após escrever bom dia */ printf("O valor de x é %7. } a saída será: O reajuste foi de 10%.2 Cprintf() Basicamente cprintf() é igual a printf(). } Observação: Caso você queira imprimir na tela os caracteres especiais ‘\’ ou ‘%’.141523. Utilize esta função para escrever na tela em posições pré-definidas.4572345. printf("\n\t\tBom dia\n").%E %f %l. 4.Informática Industrial I DAS/UFSC Tipo %c %d. x). mas usa as coordenadas atuais do cursor e da janela que forem ajustados anteriormente. y).%i %e. bem como ajustes de côr de caracteres. a. emite caracteres até aparecer caracter zero (00H) Inteiro decimal sem sinal (unsigned int) Hexadecimal Abaixo seguem alguns exemplos da formatação apresentada acima: /* Programa com exemplos da formatação da saída com Printf() */ #include <stdio.h> void main() { int reajuste = 10. printf("Bom dia"). b.h> void main() { float x. reajuste). double y = -203. \n”. int a. printf("Os valores de i.3. Marcelo Ricardo Stemmer 55 . b. você deve escreve-los na função printf() de forma duplicada. O exemplo abaixo apresenta este caso: #include <stdio. printf(“O reajuste foi de %d%%. o que indicará ao compilador que este não se trata de um parâmetro da função printf() mas sim que deseja-se imprimir realmente este caracter. j e y são: %d %d %lf \n". xxxx : xxxx (base: offset) se Far Apontador de string. a = b = 12. 7). o nome completo de uma pessoa). scanf ("%f". veja as tabelas de formatação de printf() para conhecer os parâmetros de scanf(). &anos). os parâmetros de scanf() são em geral os mesmos que os parâmetros de printf(). mas não deve ser atribuído a nenhuma variável (não deve ter parâmetros na lista de argumentos para estas especificações).3. /* lê o valor do tipo float (%f) e armazena na variável x (&x) */ } Esta função funciona como o inverso da função printf(). como visto no exemplo acima. Exemplo: /* Programa exemplo do uso de Scanf() */ #include <stdio. uma expressão de controle seguida por uma lista de argumentos separados por vírgula: scanf(“string de definição das variáveis”. Outro exemplo de scanf(): /* Segundo Programa exemplo do uso de Scanf() */ #include <stdio. O string de definição pode conter códigos de formatação. dias = anos*365.2.0f. O endereço das variáveis pode ser obtido através do operador ‘&’ apresentado na seção sobre ponteiros (ver 4. printf ("Entre com o valor de x : "). &x).\n”. Por isso.3 Scanf() A função scanf() é outra das funções de E/S implementadas em todos os compiladores C. Sua sintaxe é similar à de printf(). Para realizar este tipo de tarefa. isto é. veremos outra função mais adequada na parte referente à strings. Observe que isto torna inconveniente o uso de scanf() para ler strings compostas de várias palavras (por exemplo. } Marcelo Ricardo Stemmer 56 . as variáveis que deverão ser lidas são definidas da mesma forma que com printf(). printf(“Digite a sua idade em anos: ”). Desta forma.h> main() { float anos.Informática Industrial I DAS/UFSC 4. A lista de argumentos deve consistir nos endereços das variáveis. A função scanf() suporta a entrada via teclado. Ela é o complemento de printf() e nos permite ler dados formatados da entrada padrão (teclado). ou seja. precedidos por um sinal % ou ainda o caracter * colocado após o % que avisa à função que deve ser lido um valor do tipo indicado pela especificação. scanf(“%f”. <endereço das variáveis>). Um espaço em branco ou um CR/LF (tecla “Enter”) definem o fim da leitura. dias). printf(“Sua idade em dias e´ %.h> void main() { float x. O string de formatação de scanf()é igual ao de printf(). dias. putch() e putchar() */ #include <stdio. } */ */ */ 4. mas com eco. /* escreve valor de c1 na tela printf("\nO segundo valor digitado foi: "). recebendo-o como parâmetro. 4. /* lê caracter c1 mas não mostra na tela c2 = getche(). c1 = getch().4. ou seja.1. junto à função putch()). posteriormente.3. Esta e’ a linha dois. getche(). sem imprimir o seu valor na tela. escreve na tela os dados do cliente também de forma organizada.5 Putch() ou Putchar() A função putch() apresenta um único caracter na tela. Escreva um programa que exemplifique todos os tipos de formatações fornecidas por printf(). Ambas as funções não requerem que o usuário digite [enter] para finalizar a sua execução (veja exemplo abaixo. Escreva um programa que peça os dados da conta bancária de um cliente e.3. Marcelo Ricardo Stemmer 57 .3. A função putchar() executa a mesma operação. getchar() imprime na tela o caracter digitado.h> #include <conio. 3. Exemplo: /* Exemplo das funções: getch(). A função getche() tem a mesma operação básica. putch(c1).6 Exercícios 3. A função getch()lê um único caracter do teclado sem ecoa-lo na tela. c2.h> void main() { char c1. Escreva um programa que contenha uma única instrução e imprima na tela: Esta e’ a linha um.2. escrevendo-o na tela printf("\nO primeiro valor digitado foi: "). esta função adquire o caracter e retorna com o seu resultado. 3. Getche() e Getchar() A função getchar() aguarda a digitação de um único caracter e quando o usuário apertar a tecla [enter]. Escreva um programa que imprima na tela: Um Dois Três.Informática Industrial I DAS/UFSC 4. /* lê caracter c2. putchar(c2). 3.4 Getch().3. h> void main() { int ftemp = 0. Faça um programa que peça ao usuário para entrar com um caracter .5. Alguns são mais usados que outros. São eles: Binários: = Atribuição + Soma Subtração * Multiplicação / Divisão % Módulo (devolve o resto da divisão inteira) Unário: Menos unário (indica a troca do sinal algébrico do valor) O operador = já é conhecido dos exemplos apresentados anteriormente. pois quando dividimos 17 por 5 teremos resto 2. printf("Temperatura em graus Celsius e´ %d". Resulta o resto da divisão do inteiro à sua esquerda pelo inteiro à sua direita. Representa a atribuição da expressão à direita ao nome da variável à esquerda. ctemp).6. 17%5 tem o valor 2. Por exemplo. /* Programa Exemplo dos operadores: + . o sinal de igual não tem a interpretação dada em matemática. Os operadores + . ctemp = (ftemp . 3.* / */ #include <stdio. subtração.4 Operadores 4. } O operador módulo (%) aceita somente operandos inteiros. Utilize ponteiros para armazenar e acessar este valor. scanf("%d". Escreva um programa que peça ao usuário para entrar com um valor real (float). como é o caso dos operadores aritméticos.4. &ftemp).Informática Industrial I DAS/UFSC 3. C oferece 6 operadores aritméticos binários (operam sobre dois operandos) e um operador aritmético unário (opera sobre um operando).32)*5/9. 4. em torno de 40. int ctemp = 0.1 Operadores Aritméticos C é uma linguagem rica em operadores. A seguir está um programa que usa vários operadores aritméticos e converte temperatura Fahrenheit em graus Celsius. converta este valor para uma variável do tipo char e depois imprima o seu valor na tela em formato decimal e em formato caracter. converta este número para um valor inteiro e apresente na tela o valor deste número em formato float e o endereço da variável que o contém. printf("Digite temperatura em graus Fahrenheit: "). Em C. divisão e multiplicação. Marcelo Ricardo Stemmer 58 ./ * representam as operações aritméticas básicas de soma. Um erro comum é o de usar um único sinal de igual como operador relacional. são denominados operadores lógicos binários. Em C não existe um tipo de variável chamada “booleana”. verdade. falso). Por quê? Na verdade. este não é um erro de programa e sim um erro lógico do programador. Os operadores relacionais comparam dois operandos e retornam 0 se o resultado for falso e 1 se o resultado for verdadeiro. O compilador não o avisará que este é um erro.4. Os operadores binários disponíveis são: Operador C & | ^ ~ << >> Marcelo Ricardo Stemmer Função E lógico OU lógico Ou Exclusivo Não Desloca esquerda Desloca direita 59 .4. Ou seja. O valor zero (0) é considerado falso e qualquer valor diferente de 0 é considerado verdadeiro e é representado pelo inteiro 1. falso = %d\n".h> void main() { int verdade. verdade = (15 < 20).3 Operadores lógicos binários Este operadores são empregados para comparar os bits contidos em duas variáveis e.Informática Industrial I DAS/UFSC 4. que assuma um valor verdadeiro ou falso. falso = (15 == 20). por isso. falso. estes operadores fazem uma comparação lógica entre cada bit dos operandos envolvidos.2 Operadores Relacionais Os operadores relacionais são usados para fazer comparações. printf("Verdadeiro = %d. 4. } Note que o operador relacional “igual a” é representado por dois sinais de iguais. isto é. Os operadores relacionais disponíveis em C são: Operador C && || ! < <= > >= == != ?: Função E OU NÃO MENOR MENOR OU IGUAL MAIOR MAIOR OU IGUAL IGUAL DIFERENTE OPERADOR CONDICIONAL TERNÁRIO O programa a seguir mostra expressões booleanas como argumento da função printf(): /* Exemplo de Operadores Relacionais */ #include <stdio. como toda expressão C tem um valor verdadeiro ou falso. Por isso o resultado obtido é logicamente 0. ou seja. 0x00000000. k). ptr = &i. /* k = i XOR j */ printf("\n\t i ^ j => %x (00000011)". Operador ∗ & Função Acesso ao conteúdo do ponteiro Obtém o endereço de uma variável O programa abaixo apresenta novamente o aplicação destes operadores.2. cujo endereço está armazenado em um ponteiro. o programa faz um comparação binária ‘ou’ (^) entre estes dois números. /* atribui a j o conteúdo do endereço definido por */ /* ptr = valor de i ! */ } 4.5 Operadores Incrementais e Decrementais Uma das razões para que os programas em C sejam pequenos em geral é que C tem vários operadores que podem comprimir comandos de programas. /* Exemplo usando Operadores Binários */ #include <stdio.4. k = i << 2. } Primeiro o programa faz uma comparação binária ‘e’(&) entre o número 1 (0x00000001) e o número 2 (0x00000010). j. k). i. printf("\ti = %x (00000001)\n\tj = %x (00000010)". j).7). lógicamente. j = 2. k = i & j. 4. (0x00000100). Em seguida. ou seja. A partir deste exemplo fica clara a utilização destes operadores. Neste aspecto. Assim. O segundo operador serve para obter o endereço de uma variável. destaca-se os seguintes operadores: Marcelo Ricardo Stemmer 60 . em binário.Informática Industrial I DAS/UFSC A seguir temos um exemplo da aplicação deste operadores. /* Operadores de Ponteiros */ void main() { int i. 3. /* k = i deslocando 2 bits à esquerda (4) */ printf("\n\t i << 2 => %x (00000100)". /* atribui a ptr o endereço da variável i */ j = *ptr. k. k). i = 1. /* k = i AND j */ printf("\n\t i & j => %x (00000000)". o programa desloca o número 1 em duas casas para a esquerda. representado no programa pelo operador << 2. *ptr. k = i ^ j.4. Por fim. (0x00000011). resultando agora. o resultado é o número 4 ou. j.4 Operadores de Ponteiros Estes operadores já foram apresentados anteriormente na seção sobre ponteiros (ver 4.h> void main() { int i. O primeiro operador serve para acessar o valor da variável. n é incrementado depois de seu valor ser usado. /* incrementa i */ i = i . int *ptr = 0. depois o resultado é atribuído a ‘k’ e. faça uso de parênteses para guiar a execução do programa evitando que o compilador não compreenda a ordem correta de executar a operação. Abaixo. } Vamos analisar duas expressões seguintes. O primeiro modo é chamado pré-fixado e o operador aparece antes do nome da variável. Dica: Para evitar problemas. o resultado é atribuído a ‘k’. a) k = 3*n++. m. /* recebe o endereço de i */ (*ptr)++. x. i = i + 1. /* Operadores de Incremento */ #include <stdio. finalmente. depois ‘n’ é multiplicado por 3 e. /* incrementa valor de i */ ptr++. O segundo é o modo pós-fixado em que o operador aparece seguindo o nome da variável. ressaltando esta questão. Aqui. n. b) k = 3*++n.Informática Industrial I DAS/UFSC Operador ++ -- Função Incrementa em 1 Decrementa em 1 O operador de incremento (++) incrementa seu operando em 1. /* incrementa em 2 Bytes (1 inteiro ocupa 2 Bytes) */ /* o valor do endereço apontado pelo ponteiro ptr */ } Marcelo Ricardo Stemmer 61 . primeiro ‘n’ é incrementado em 1. x = ++n = %d. printf("O resultado e:\n n = %d. n = m = 5. Em ambos os casos. primeiro ‘n’ é multiplicado por 3. por fim. y.\n m = %d. y). x. a variável é incrementada.". e quando n++ estiver numa instrução. /* incrementa i */ i++. Este operador trabalha de dois modos.1. /* decrementa i */ ptr = &i. x = ++n. y = m++ = %d.h> void main() { int n. m. temos um outro exemplo dos operadores incrementais apresentado várias aplicações destes operadores: /* Operadores Incrementais 2 */ void main() { int i = 10. y = m++. O programa abaixo mostra um exemplo destes operadores. n é incrementada antes de seu valor ser usado. Aqui. Porém quando ++n é usado numa instrução. /* decrementa i */ i--. ‘n’ é incrementado de 1. podendo conter qualquer dado. A &= B. eqüivale à x = (x)op(exp). A %= B. tome cuidado ao manipular ponteiros para não acessar variáveis com uso desconhecido. Se o valor deste ponteiro for acessado. << B. printf("Total=%d\n". printf("Total=%d\n". Esta instrução irá altera o endereço armazenado em ptr. o dado representado por este ponteiro não tem nenhuma relação mais com a variável ‘i’. >> B.6 Operadores de Atribuição O operador básico de atribuição (=) pode ser combinado com outros operadores para gerar instruções em forma compacta. A |= B.Informática Industrial I DAS/UFSC Atenção para a última instrução ptr++. A /= B. . ∗ B. total). Exemplo: /* Operadores de Atribuição */ #include <stdio. } Marcelo Ricardo Stemmer total). printf("Total=%d\n". A >>= B. Operador C: = += -= ∗= /= %= >>= <<= &= |= ^= Função: A = B A += B. Por isso. total += 1. & B. Isto poderá fazer com que o seu programa gere erros fatais para o sistema operacional. total). | B. printf("Total=%d\n".4. total *= cont. / B.B. ^ B. A operação consiste em atribuir um novo valor à variável que dependerá do operador e da expressão a direita. A <<= B. Se x é uma variável. total ^= 2. 62 . 4. total). total). int cont = 10.h> void main() { int total = 0. ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ A A A A A A A A A A = = = = = = = = = = A A A A A A A A A A + B. Cada um destes operadores é usado com um nome de variável à sua esquerda e uma expressão à sua direita. A -= B. % B. printf("Total=%d\n". A ∗= B. total <<= 2. A ^= B. exp uma expressão e op um operador. então: x op= exp. Informática Industrial I DAS/UFSC 4.4.7 O Operador Lógico Ternário O operador condicional possui uma construção um pouco estranha. É o único operador em C que opera sobre três expressões. Sua sintaxe geral possui a seguinte construção: exp1 ? exp2 : exp3 A exp1 é avaliada primeiro. Se seu valor for diferente de zero (verdadeira), a exp2 é avaliada e seu resultado será o valor da expressão condicional como um todo. Se exp1 for zero, exp3 é avaliada e será o valor da expressão condicional como um todo. Na expressão: max = (a>b)?a:b; a variável que contém o maior valor numérico entre a e b será atribuída a max. Outro exemplo: abs = (x > 0) ? x : -x; /* abs é o valor absoluto de x */ A expressão printf(“ %d é uma variável %s !”, x, ((x%2)?”Impar”:”Par”); imprime ímpar se x for um número “ímpar”, caso contrário imprimirá “par”. 4.4.8 Precedência O operador ! é o de maior precedência, a mesma que a do operador unário. A tabela seguinte mostra as precedências dos operadores: Operadores ! - ++ -* / % + < > <= >= == != && || = += -= *= Tipos Unários; não lógicos e menos aritméticos Aritméticos Aritméticos Relacionais Relacionais Lógico & Lógico OU Atribuição /= %= 4.4.9 Exercícios: 4.1. Qual é o resultado da seguinte expressão: int a = 1, b = 2, c = 3; int result = ++a/a&&!b&&c||b--||-a+4*c>!!b; 4.2. Escreva uma expressão lógica que resulte 1 se o ano for bissexto e 0 se o ano não for bissexto. Um ano é bissexto se for divisível por 4, mas não por 100. Um ano também é bissexto se for divisível por 400. 4.3. Faça um programa que solicite ao usuário o ano e imprima “Ano Bissexto” ou “Ano Não-Bissexto” conforme o valor da expressão do exercício anterior. Utilize o operador condicional. 4.4. Num cercado, há vários patos e coelhos. Escreva um programa que solicite ao usuário o total de cabeças e o total de pés e determine quantos patos e quantos coelhos encontram-se nesse cercado. Marcelo Ricardo Stemmer 63 Informática Industrial I DAS/UFSC 4.5. Uma firma contrata um encanador a 20.000,00 por dia. Crie um programa que solicite o número de dias trabalhados pelo encanador e imprima a quantia líquida que deverá ser paga, sabendo-se que são descontados 8% para imposto de renda. 4.6. Faça um programa que solicite um caractere do teclado por meio da função getch(); se for uma letra minúscula imprima-a em maiúsculo, caso contrário imprima o próprio caracter. Use uma expressão condicional 4.7. Faça um programa que solicite ao usuário uma seqüência binária com 16 bits. Transforme esta seqüência de 0 e 1 em um número inteiro. Depois manipule este número inteiro para verificar se os bits 0, 3, 7, 14 estão habilitados (valor igual a 1). Peça a usuário se ele deseja modificar algum bit específico da palavra. Se ele quiser, modifique o bit desejado para o valor por ele fornecido. 4.5 Laços Em C existem 3 estruturas principais de laços: o laço for, o laço while e o laço do-while. 4.5.1 O Laço For O laço for engloba 3 expressões numa única, e é útil principalmente quando queremos repetir algo um número fixo de vezes. Sintaxe: for(inicialização ; teste ; incremento) instrução; Os parênteses seguindo a palavra chave for contém três expressões separadas por ponto-evírgulas, chamadas respectivamente de : “expressão de inicialização”, “expressão de teste” e “expressão de incremento”. As 3 expressões podem ser compostas por quaisquer instruções válidas em C. • Inicialização: executada uma única vez na inicialização do laço. Serve para iniciar variáveis. • Teste: esta é a expressão que controla o laço. Esta é testada quando o laço é iniciado ou reiniciado. Sempre que o seu resultado for verdadeiro, as instruções do laço serão executadas. Quando a expressão se tornar falsa, o laço é terminado. • Incremento: define a maneira como a variável de controle do laço será alterada cada vez que o laço é repetido (conta++). Esta instrução é executada, toda vez, imediatamente após a execução do corpo do laço. for( conta = 0; conta < 10; conta++ ) printf(“conta=%d\n”, conta); Exemplo: /*Laço For 1*/ #include <stdio.h> void main() { int conta; for(conta = 0; conta < 10; conta += 3) printf("conta=%d\n", conta); } Marcelo Ricardo Stemmer 64 Informática Industrial I DAS/UFSC Qualquer uma das expressões de um laço for pode conter várias instruções separadas por vírgulas. A vírgula é na verdade um operador C que significa “faça isto e isto”. Um par de expressões separadas por vírgula é avaliado da esquerda para a direita. /* Forma Flexível do Laço for */ #include <stdio.h> void main() { int x, y; for( x=0, y=0; x+y < 100; x = x+1, y++) printf("%d\n", x+y); } Podemos usar chamadas a funções em qualquer uma das expressões do laço. Qualquer uma das três partes de um laço for pode ser omitida, embora os pontos-e-vírgulas devam permanecer. Se a expressão de inicialização ou a de incremento forem omitidas, elas serão simplesmente desconsideradas. Se a condição de teste não está presente é considerada permanentemente verdadeira. O corpo do laço pode ser composto por várias instruções, desde que estas esteja delimitadas por chaves { }. O corpo do laço pode ser vazio, entretanto o ponto-e-vírgula deve permanecer para indicar uma instrução vazia. Quando um laço está dentro de outro laço, dizemos que o laço interior está aninhado . Para mostrar esta estrutura preparamos um programa que imprime a tabuada. /* tabuada */ #include <stdio.h> void main() { int i,j,k; printf("\n"); for(k=0; k<=1; k++) { printf("\n"); for(i=1; i<5; i++) printf("Tabuada do %3d ", i+4*k+1); printf("\n"); for(i=1; i<=9; i++) { for(j = 2+4*k; j<=5+4*k; j++) printf("%3d x%3d = %3d ", j, i, j*i); printf("\n"); } } } 4.5.2 O Laço While O laço while utiliza os mesmos elementos que o laço for, mas eles são distribuídos de maneira diferente no programa. Sintaxe: while(expressão de teste) instrução; Marcelo Ricardo Stemmer 65 Informática Industrial I DAS/UFSC Se a expressão de teste for verdadeira (diferente de zero), o corpo do laço while será executado uma vez e a expressão de teste é avaliada novamente. Este ciclo de teste e execução é repetido até que a expressão de teste se torne falsa (igual a zero), então o laço termina. Assim como o for, o corpo do laço while pode conter uma instrução terminada por (;), nenhuma instrução desde que possua um (;) ou um conjunto de instruções separadas por chaves { }. Abaixo temos um exemplo, onde um laço while substituiu um antigo laço for. /*Laço While 1*/ #include <stdio.h> void main() { int conta = 0; while(conta < 10) { printf("conta=%d\n", conta); conta++; } } Quando se conhece a priori o número de loops que o laço deve fazer, recomenda-se o uso do laço for. Caso o número de iterações dependa das instruções executadas, então recomenda-se o uso do laço while. Os laços while podem ser aninhados como o laço for. C permite que no interior do corpo de um laço while, você possa utilizar um outro laço while. 4.5.3 O Laço Do-While O laço Do-While cria um ciclo repetido até que a expressão de teste seja falsa (zero). Este laço é bastante similar ao laço while. A diferença é que no laço do-while o teste de condição é avaliado depois do laço ser executado. Assim, o laço do-while é sempre executado pelo menos uma vez. A sintaxe é a seguinte: do { instrução; } while(expressão de teste); Embora as chaves não sejam necessárias quando apenas uma instrução está presente no corpo do laço do-while, elas são geralmente usadas para aumentar a legibilidade. Exemplo usando os laços while e do-while: /* Programa de Exemplo do laço Do-While */ #include <stdio.h> #include <conio.h> #include <stdlib.h> /* requerida para rand() */ void main() { char ch, c; int tentativas; do { ch = rand()%26 + 'a'; tentativas = 1; Marcelo Ricardo Stemmer 66 O nome segue as convenções de nomes de variáveis C. seu código decima e hexadecimal. Escreva um programa que imprima os caracteres da tabela ASCII de códigos de 0 a 255. O programa deve imprimir cada caracter.Informática Industrial I DAS/UFSC printf("\nDigite uma letra de 'a' a 'Z':\n"). printf("\nQuer jogar novamente? (s\\n): "). } printf("\n%c e´ correto". Escreva um programa.5. o computador primeiro executa o incremento do laço e. o teste condicional. printf("\nvoce acertou em %d tentativas".5.c). A instrução goto tem duas partes: a palavra goto e um nome. Para que esta instrução opere.\n”). A instrução goto causa o desvio do controle do programa para a instrução seguinte ao rótulo com o nome indicado. Tente novamente. tentativas). O comando continue força a próxima interação do laço e pula o código que estiver abaixo. mas seu uso é desnecessário e desaconselhado. Por exemplo: goto parte1. } 4. tentativas++. 4. anteriores a era da programação estruturada.4 Break e Continue O comando break pode ser usado no corpo de qualquer estrutura do laço C. parte1: printf(“Análise dos Resultados. Enquanto o usuário não pressionar a tecla ESC de código 27. que leia caracteres do teclado.5 Goto O comando goto faz com que o programa pule para a instrução logo após o “label” passado como parâmetro. Os dois pontos são usados para separar o nome da instrução.5. os caracteres lidos não são ecoados no Marcelo Ricardo Stemmer 67 . Nos laços while e do-while um comando continue faz com que o controle do programa vá diretamente para o teste condicional e depois continue o processo do laço. No caso do laço for.6 Exercícios 5. while((c=getch())!= ch) { printf("%c e´ incorreto. e finalmente faz com que o laço continue. Se o comando break estiver em estruturas de laços aninhados. depois. 4. Este comando era muito usado nos primeiros programas de computador.c). }while(getche()=='s'). Foi implementado somente para manter a compatibilidade com outros compiladores e para evitar a necessidade de reescrever inúmeras bibliotecas de funções já existentes antes do advento da programação estruturada. 5. deve haver um rótulo (label) em outra parte do programa.2. Um rótulo é um nome seguindo por dois pontos. Monte uma tabela usando os parâmetros de formatação de printf().1. afetará somente o laço que o contém e os laços internos a este. \n\n". Causa a saída imediata do laço e o controle passa para o próximo estágio do programa. utilizando um laço while. 5. C oferece 3 principais estruturas de decisão: if. Sintaxe: if(expressão de teste) instrução.6. Os comandos de decisão permitem determinar qual é a ação a ser tomada com base no resultado de uma expressão condicional. o programa irá executar uma instrução ou um conjunto delas. Marcelo Ricardo Stemmer 68 . Elabore um programa que solicite um número inteiro ao usuário e crie um novo número inteiro com os dígitos em ordem inversa.6 Comandos para Tomada de Decisão Uma das tarefas fundamentais de qualquer programa é decidir o que deve ser executado a seguir. ou seja. switch. Como os laços. Dizemos então que o if interno está aninhado. 4. if-else. O programa abaixo mostra exemplos do uso e da sintaxe dos comandos if.Informática Industrial I DAS/UFSC vídeo. se for qualquer outro caracter. o programa a imprime em maiúsculo e. Escreva um programa que desenhe uma moldura na tela do micro. /* Programa exemplo para o comando if */ #include <stdio. Como C não possui variáveis booleanas. Caso se utilize para um conjunto de instruções. O primeiro if mostra a forma aninhada do comando if. 5. desenhando um sol com as suas iniciais no meio da tela e escrevendo “Feliz Natal” e o seu nome embaixo. se o valor for igual a zero (0) a condição será falsa e se o valor for diferente de zero. if(ch >= 'A') /* Dois comandos if aninhados */ if(ch <= 'z') printf("\n Voce digitou um caracter valido!").3.4. o teste sobre a condição opera como os operadores condicionais. printf("Digite uma letra de 'a' a 'Z':"). o segundo apresenta a sintaxe básica e o último um exemplo onde o comando if executa um bloco de instruções.1 If O comando if é usado para testar uma condição e caso esta condição seja verdadeira. a condição será verdadeira. 4. ele mesmo é impresso.h> void main() { char ch.h> #include <conio. Este é um dos comandos básicos para qualquer linguagem de programação. o comando if pode ser usado para uma única instrução ou para um conjunto delas. Estas estruturas são o tema desta seção. Por exemplo o número 3567 deve ser escrito 7653. Se o caracter lido for uma letra minúscula. ch = getche(). Isto significa que podemos selecionar entre ações alternativas dependendo de critérios desenvolvidos no decorrer da execução do programa. este conjunto deve ser delimitado por chaves { e }. Um comando if pode estar dentro de outro comando if. Informática Industrial I DAS/UFSC if(ch == 'p') /* Forma básica de um comando if */ printf("\nVoce pressionou a tecla 'p'!").6. Embora construções if-else possam executar testes para escolha de uma entre várias alternativas. ou if-else dentro do bloco de instruções após o else. } } 4. /* cor escura */ else printf("\xB0"). muitas vezes são deselegantes. y++) /* passo de descida */ { for(x=1. A instrução switch consiste na palavra-chave switch seguida do nome de uma variável ou de um número constante entre parênteses. O comando else. ch = getche(). Exemplo: /* Programa exemplo do If-Else */ #include <stdio. x<24. y. if(ch != 'p') /* Comando if executando um bloco de instruções */ { printf("\nVoce não digitou a tecla 'p'!”).h> void main() { int x. quando associado ao if.3 Switch O comando switch permite selecionar uma entre várias ações alternativas. Sintaxe: if(expressão de teste) instrução_1. /* cor clara */ printf("\n"). x++) /* passo de largura */ if(x==y || x==24-y) /* diagonal? */ printf("\xDB"). O if-else também permite o aninhamento de outros comandos if. y<24. O corpo do comando switch é composto de vários Marcelo Ricardo Stemmer 69 ."). O comando switch tem um formato limpo e claro. else instrução_2.2 If-Else No exemplo anterior. o comando if executará um única instrução ou um grupo de instruções se a expressão de teste for verdadeira e não fará nada se a expressão de teste for falsa. for(y=1. printf(“\n Digite qualquer caracter para finalizar.6. executará uma instrução ou um grupo de instruções entre chaves se a expressão de teste do comando if for falsa. /* Nova Linha */ } } 4. default: instrução. O ano deve ser maior ou igual a 1600. instrução. break. uma ou mais instruções seguindo cada caso. Um caso default é opcional. instrução.h> #include <conio. scanf("%d/%d/%d". O corpo de um switch deve estar entre chaves. long int F = 0. Não pode haver casos com rótulos iguais. instrução. } Você não poderá usar uma variável nem uma expressão lógica como rótulo de um caso. &A). Pode haver nenhuma. O comando break causa a saída imediata de todo o corpo do switch. todas as instruções após o caso escolhido serão executadas. case constante3: instrução: instrução: break. /* Exemplo do comando switch */ /* Calcula o dia da semana a partir de uma data */ #include <stdio. &M. Geralmente. pois nesta data houve uma redefinição do calendário. a última instrução é break. a execução começa nele. i. O corpo de cada caso é composto por qualquer número de instruções. Sintaxe: switch(variável ou constante) { case constante1: instrução.Informática Industrial I DAS/UFSC casos rotulados por uma constante e opcionalmente um caso default. Se nenhum caso for satisfeito e existir um caso default. A. Marcelo Ricardo Stemmer 70 . mesmo as que pertencem aos casos seguintes. A expressão entre parênteses após a palavra-chave switch determina para qual caso será desviado o controle do programa. do { do { printf("\nDigite uma data na forma dd/mm/aaaa: "). Estas instruções não necessitam estar entre chaves.h> void main() { int D. case constante2: instrução. break. M. a execução começará nele. A seguir apresentamos um exemplo que calcula o dia da semana a partir de uma data. Na falta do comando break. Se o rótulo de um caso for igual ao valor da expressão do switch. &D. break. A seqüência de Fiboncci é a seguinte: 1.Informática Industrial I DAS/UFSC } while(A<1600 || M<1 || M>12 || D<1 || D>31). break.3.4. switch(F) { case 0: printf("\nDomingo"). 13. i *= . F+= A/4 . Crie um programa que desenhe na tela o seu quadro de horários deste semestre.3. F -= i. case 2: printf("\nTerca-Feira"). } else i = . 3. 2. Seu programa deve somar todos os inteiros entre b e c que sejam divisíveis por a. 6. break. b. F %= 7.75. 8.4 Exercícios 6. e c onda a é maior que 1.2. case 5: printf("\nSexta-Feira"). 5. 1. /* Tecla ESC não for pressionada */ } 4.. . i = A/100 + 1. 6. break.i.1. break. if(M<3) { A--. Escreva um programa que solicite ao usuário três números inteiros a. F = A + D + 3*(M-1) . Marcelo Ricardo Stemmer 71 .1. Crie um programa que desenhe na tela um tabuleiro de xadrez. 6. case 3: printf("\nQuarta-Feira"). 21. break. i = 0. case 1: printf("\nSegunda-Feira").6. break.4*M+2. case 4: printf("\nQuinta-Feira"). } }while(getche()!=27). case 6: printf("\nSabado").. 4.1 Sintaxe A estrutura de uma função C é bastante semelhante à da função main(). Uma vez implementada corretamente esta tarefa. Por exemplo. Nome indica qual é o nome da função. No entanto...Informática Industrial I DAS/UFSC Os dois primeiros termos são iguais a 1. pois a função já fornece este serviço de forma adequada.> <. A lista de instruções a serem executadas pela função vem após a lista de parâmetros é deve ser delimitada por chaves { e }. o nome desta deve ser seguido por parênteses ( ) sem nenhum parâmetro no seu interior.. Mesmo quando uma função não necessita de parâmetros. facilitam bastante a organização modular do programa. return não precisa ser o último comando da função. Sintaxe: <tipo retorno> <nome>(<tipo parâmetro> <nome parâmetro>. Uma função é uma unidade de código de programa autônoma projetada para cumprir uma tarefa particular. A principal razão da existência de funções é impedir que o programador tenha que escrever o mesmo código repetidas vezes. O programa deve perceber quando o jogo acabou e anunciar o vencedor. Por exemplo: se o número fornecido pelo usuário for igual a 7. basta usar a sua função correspondente. o programa deverá imprimir 13. return <expressão ou valor compatível com o tipo de retorno>. Cada termo seguinte é igual `a soma dos dois anteriores. permitem que uma função retorne mais do que uma única variável contendo o resultado. Marcelo Ricardo Stemmer 72 . <. Infelizmente.>) { <declarações locais>. onde o programa desenha na tela um tabuleiro e você pede a dois usuários (A e B) na respectiva ordem. que jogada eles querem realizar e depois atualiza o desenho. <comandos>. quando bem empregadas. Algumas linguagens. Um função pode ter tantos argumentos quanto você queira definir. como Matlab. 6. As instruções utilizam os parâmetros para executarem a tarefa. As funções. primeiramente declara-se e inicializa-se as variáveis locais e posteriormente temos os comandos da função (instruções). } O tipo de retorno define o tipo de dado o qual a função retornará com o resultado de sua execução. não nos preocupamos como o programa realiza esta tarefa. Dentro do bloco de instruções da função. Em seguida temos a lista de argumentos da função inseridos entre os parênteses após o nome da função e separados por vírgulas. O comando return encerra a função e retorna ao ponto do programa onde esta foi chamada..7.7 Funções As funções servem para agrupar um conjunto de instruções de acordo com a tarefa que elas desempenham. Escreva um programa que solicite ao usuário o número do termo e calcule o valor do termo. Implemente um jogo da velha. 4. quando usamos printf() para imprimir informações na tela. A única diferença é que main()possui um nome especial pois a função main()é a primeira a ser chamada quando o programa é executado. permitem a reutilização de partes do programa e facilitam a sua manutenção. Os argumentos são declarados no cabeçalho da função com o tipo parâmetro e em seguida o nome do parâmetro. uma função em C só pode retornar um resultado e este é repassado através de return.5. uma função chamada não pode alterar o valor de uma variável da função que chama. Os parênteses que seguem o nome são necessários para que o compilador possa diferenciar a chamada a uma função de uma variável que você esqueceu de declarar. /* Beep 1 */ for(k=1. ela só pode alterar sua cópia temporária.7.Exemplo do uso de funções */ /* Testa a função doisbeep */ #include <stdio. deve ser encerrada por ponto-e-vírgula. uma função que dentro do seu corpo de instruções {} existe uma chamada de função a si própria.h> /* doisbeep() */ /* toca o alto-falante duas vezes */ doisbeep() { int k. Entretanto.2 Exemplos Abaixo apresentamos um exemplo do emprego das funções: /* Beeptest . você faça uma chamada a própria função e você já terá implementado uma função recursiva. o compilador C considera que o tipo de retorno adotado é void. Quando uma função não tem um tipo de retorno definido. tenha cuidado com funções recursivas para não fazer com que o programa entre em loops infinitos. Do mesmo modo que chamamos uma função de biblioteca C (printf(). isto é. O comando return é utilizado quando queremos finalizar esta função antes de executar todas as instruções. Basta que. } A declaração da função doisbeep() é equivalente a seguinte declaração: void doisbeep(void) Isto acontece pois quando o tipo retornado ou o parâmetro for void (representando que nenhum dado será passado). na definição de uma função.. /* Beep 2 */ } /* função principal */ void main() { doisbeep(). Visto que a chamada de uma função constitui uma instrução de programa.Informática Industrial I DAS/UFSC Funções com tipo de retorno void. C permite a criação de funções recursivas. k++) /* Gera um pequeno delay */ . getche(). Entretanto. . Isto significa que à função chamada é dada uma cópia dos valores dos argumentos.. k<10000. ele aparece sem nenhum parâmetro a sua direita. não utilizam o comando return pois estas não retornam nenhum tipo de dado. Exemplo: Marcelo Ricardo Stemmer 73 . o ponto-e-vírgula não pode ser usado. Neste caso. todos os argumentos de funções são passados “por valor”. e ela cria outras variáveis temporárias para armazenar estes valores. printf("\x7"). Este caso funciona como uma chamada para uma outra função qualquer. A diferença principal é que. printf("\x7"). na definição da função. 4.) chamamos nossas próprias funções. getche(). Em C. somente o ponto-e-vírgula. doisbeep(). em C. printf("Digite um caracter: "). estes podem ser omitidos já que C considera este tipo como default. int pot). } Cada chamada recursiva da função “fatorial” coloca mais uma variável i do tipo long int na pilha (stack). local */ int i = 0. i < pot. /* retorna float */ } /* potencia() */ /* eleva a uma potência positiva.h> float area(float r).2)). pois estas podem causar um “estouro” da pilha. printf("Digite o raio da esfera: "). else return 1. printf("A area da esfera e' %.2f". for(i = 1. void main() { float raio = 0. area(raio)). int pot) { float result = 0. } /* area() */ /* retorna a área da função */ float area(float r) /* definição da função */ { return (4*3. } 4.Exemplo de função */ /* calcula a área da esfera */ #include <stdio.7.14159*potencia(r. /* declaração de var. /* Indica que houve erro */ if(pot == 0) return 1. na forma: <tipo retorno> <nome da função> (<tipo dos parâmetros>).3 Prototipagem Toda função que for utilizada em main() e que for declarada após main(). O protótipo consiste de uma versão simplificada do cabeçalho da função. scanf("%f". Marcelo Ricardo Stemmer 74 . um parâmetro dado */ float potencia(float num. i++) result *= num. if(pot < 0) return 0. &raio). /* Esfera . /* declaração do protótipo da função */ float potencia(float num. tem que ser prototipada. É portanto necessário ter cuidado com funções recursivas.Informática Industrial I DAS/UFSC long int Fatorial(long int i) { if(i > 1) return i*Fatorial(i-1). return result. result = num. y = Raiz(x).y.2 Extern Todas as funções C e todas as variáveis declaradas fora de qualquer função têm a classe de armazenamento extern. Feita a declaração do protótipo da função. Este tipo de declaração. int n. A classe de variáveis automáticas pode ser explicitada usando-se a palavra auto. isto é.4. As duas declarações abaixo são equivalentes: auto int n. por isso é que o protótipo de uma função tem um papel importante para a organização e flexibilidade do seu código fonte. static e register.h> Marcelo Ricardo Stemmer 75 .7. 4. A declaração de variáveis externas é feita da mesma maneira como declaramos variáveis dentro do bloco de uma função. 4. Tais variáveis são chamadas “locais” ou “automáticas” e são criadas quando a função é chamada e destruídas quando a função termina a sua execução.1 Auto As variáveis que temos visto em todos os nossos exemplos estão confinadas nas funções que as usam.4. A palavra extern indica que a função usará mais uma variável externa. x = 4. Variáveis automáticas são as mais comuns dentre as 4 classes.0.7.7. As variáveis declaradas dentro de uma função são automáticas por “default”. Variáveis com este atributo serão conhecidas por todas as funções declaradas depois dela. } double Raiz(double valor) { /* <calculo da raiz de valor>. Abaixo temos um exemplo: /* Exemplo da variável de tipo extern */ #include <stdio. extern. entretanto. esta poderá ser chamada ou definida em qualquer parte do seu programa. O programa anterior e o exemplo abaixo apresentam a forma de se criar o protótipo de uma função.4 Classes de Armazenamento Todas as variáveis e funções em C têm dois atributos: um tipo e uma classe de armazenamento. As 4 classes de armazenamento serão vistas a seguir: auto. */ return valor. não é obrigatório se a definição original ocorre no mesmo arquivo fonte. como veremos mais a frente. nenhuma prototipagem é necessária. double Raiz(double). } 4. Os tipos nós já conhecemos. Uma variável definida fora de qualquer função é dita extern. são visíveis ou acessíveis somente às funções onde estão declaradas. /* protótipo */ main() { double x.Informática Industrial I DAS/UFSC Se main() for declarado por último. Protótipos são também utilizados para escrever programas compostos de vários módulos. \n").7.h> /* declaração de protótipo */ void soma(). scanf("%d".Informática Industrial I DAS/UFSC /* Declaração de variáveis extern */ int teclanum. printf("Digite teclanum: "). /* uso do tipo static */ #include <stdio. } 4. parimpar(). } /* parimpar() */ /* checa se teclanum é par ou impar */ void parimpar(void) { extern teclanum. pois são conhecidas somente as funções que as declaram e de outro lado se assemelham às externas pois mantém seus valores mesmo quando a função termina. /* Declaração de funções */ void parimpar(void). soma(). Marcelo Ricardo Stemmer 76 . &teclanum). \n"). i++.4. else printf("teclanum e' par. } /* soma() */ /* usa variável static */ void soma() { static int i = 0. O mais elementar é permitir a variáveis locais reterem seus valores mesmo após o término da execução do bloco onde estão declaradas.3 Static Variáveis static de um lado se assemelham às automáticas. Declarações static têm dois usos importantes e distintos. if(teclanum % 2) printf("teclanum e' impar. void main() { extern teclanum. void main() { soma(). soma(). justamente. i). i++) printf(“Número: %d”.4 Variáveis Estáticas Externas O segundo e mais poderoso uso de static é associado a declarações externas. register int i. Um número primo é qualquer inteiro positivo divisível apenas por si próprio e por 1.7. retorne 1. 4. for(i = 0.2. Como os computadores possuem um número limitados de registradores (depende da CPU em uso). Variáveis que usualmente utilizam este tipo são as variáveis de laços e argumentos de funções. utilizando variáveis static para armazenar o valor da semente. o seu programa também só poderá utilizar um número limitado de variáveis register. onde ‘n’ será fornecido pelo usuário. Se todos os registradores estiverem ocupados o computador simplesmente ignora a palavra register das nossas declarações.4. Marcelo Ricardo Stemmer 77 . você pode definir uma variável static em um arquivo fonte onde estão todas as funções que necessitam acesso a esta variável. Crie um programa para gerar números aleatórios. para que possamos aumentar a velocidade do programa. caso contrário retorne 0.1.7.Informática Industrial I DAS/UFSC printf("i = %d\n". Opera como uma variável do tipo auto. 4.4. i< 10. isto é feito diretamente em um registrador da CPU. Mas isto não nos impede de declarar quantas variáveis register quisermos. se este número for primo. Escreva uma função que receba um inteiro positivo e. a saída será: i = 0 i = 1 i = 2 4. Faça um programa que imprima na tela os ‘n’ primeiros números primos. i). Os demais arquivos fontes não terão acesso a ela. isto é. permite um mecanismo de “privacidade” muito importante à programação modular.7. o programa torna-se mais rápido usando register. No caso das variáveis tipo register.5 Exercícios 7.5 Register A classe de armazenamento register indica que a variável associada deve ser guardada fisicamente em um lugar onde possa ser acessada muito mais rapidamente. mas possui um tempo de acesso muito menor. A diferença entre variáveis externas e externas estáticas é que variáveis externas podem ser usadas por qualquer função abaixo de (a partir das) suas declarações. enquanto que variáveis externas estáticas somente podem ser usadas pelas funções de mesmo arquivo-fonte e abaixo de suas declarações. Isto é. Junto a construções externas. Portanto. Um registrador da máquina é uma área da CPU onde pode-se armazenar variáveis do tipo inteiro ou char. } Observe que i não é inicializada a cada chamada de soma(). 7. podemos criar uma constante para conter o valor de pi: #define PI 3. baseado em instruções chamadas diretivas. Quando o compilador encontra #define. A diretiva #define pode ser usada não só para definir constantes. se a função recebe n = 5.h> #define ERRO printf("\n Erro. As instruções desta linguagem são executadas antes do programa ser compilado e têm a tarefa de alterar os códigos-fonte.2 e 4. Diretivas do pré-processador são instruções para o compilador propriamente dito. Um ou mais espaços separam o identificador do texto. Por exemplo. na sua forma de texto.14159). Escreva um programa que solicite ao usuário um ano e imprima o calendário desse ano. Diretivas do pré-processador seriam instruções desta linguagem. elas operam diretamente no compilador antes do processo de compilação ser iniciado. mas não farão parte do programa que compilamos.14159 e depois utilizar o valor desta constante no programa: area_esfera = (4*raio*raio*PI). para tal implemente uma função recursiva. ele substitui cada ocorrência de PI no programa por 3. Instruções para o pré-processador devem fazer parte do texto que criamos.14159. mas é costume serem colocadas no início do programa. deve retornar 15. Ele é executado automaticamente antes da compilação. Por exemplo. O primeiro termo após a diretiva #define (PI). 7.5. como mostra o exemplo seguinte: #include <stdio. Organize o programa de forma adequada através de funções. diretivas do pré-processador são instruções para o compilador.Informática Industrial I DAS/UFSC 7. é chamada “identificador”.8 Diretivas do Pré-Processador O pré-processador C é um programa que examina o código fonte em C e executa certas modificações nele. Escreva uma função recursiva de nome soma() que receba um número inteiro positivo n como argumento e retorne a soma dos n primeiros números inteiros. pois são retiradas do texto antes da compilação. antes de main().3.8. O pré-processador faz parte do compilador e pode ser considerado uma linguagem dentro da linguagem C. Crie um programa para calcular o fatorial de um número. Mais precisamente. ou antes do começo de uma função particular.4.3. 7. Observe também que não há ponto-e-vírgula após qualquer diretiva do pré-processador. Linhas normais de programa são instruções para o microprocessador. que será substituída. é chamada ”texto”. Note que só podemos escrever um comando deste tipo por linha. Todas as diretivas do pré-processador são iniciadas com o símbolo # (sustenido). que será procurada.\n") Marcelo Ricardo Stemmer 78 . pois: 15 = 1 + 2 + 3 + 4 + 5 4.1 Diretiva #define A diretiva #define pode ser usada para definir constantes simbólicas com nomes apropriados. Utilize os programas desenvolvidos nos exercícios 4. As diretivas podem ser colocadas em qualquer parte do programa. O segundo termo (3. 4. coloque parênteses envolvendo o texto todo de qualquer diretiva #define que use argumentos. float num2.2f\n”. Eis um exemplo que ilustra como um macro é definido e utilizado: /* Exemplo do uso de Macros*/ #include <stdio.y) ((x)+(y)) Como macros são simples substituições dentro dos programas.4) por 3+4. a execução do programa será mais rápida que a chamada a uma função toda vez que se fizer necessário.n). O compilador substituíra SOMA(3. bem como envolvendo cada argumento.Informática Industrial I DAS/UFSC void main() { int i. portanto PRN(num1) será substituído por printf(“%. Para evitar isto.y) x+y ans = 10 * SOMA(3. PRN(num2). porque o espaço entre PR e (n) é interpretado como o fim do identificador. printf("\nDigite um numero entre 0 a 100: "). void main() { float num1 = 27.8. Por exemplo: #define SOMA(x. o seu código aparecerá em cada ponto do programa onde forem usadas. scanf("%d". PRN(num1). } 4. } Quando você usar a diretiva #define nunca deve haver espaço em branco no identificador. a instrução #define PRN (n) printf(“%.2f\n".2f\n”. Em contrapartida.2 Macros A diretiva #define tem a habilidade de usar argumentos. e o computador executará: ans = 10 * 3+4.4).0/3. ou seja. &i). pois permitem a utilização de nomes sugestivos para expressões. Toda ocorrência de PRN(n) em seu programa é substituída por printf(“%.num1). n age realmente com um argumento. Por segurança.h> #define PRN(n) printf("%. um erro. Assim. O n na definição do macro é substituído pelo nome usado na chamada ao macro em seu programa. num2 = 1. o código do programa Marcelo Ricardo Stemmer 79 . Assim. Por exemplo.2f\n”.25.n) não trabalhará corretamente. você deve definir a macro da seguinte forma: #define SOMA(x. Uma diretiva #define com argumentos é chamada de macro e é bastante semelhante a uma função. Macros aumentam a clareza do código. Para definir um texto ”muito grande” devemos delimitar a linha anterior com uma barra invertida \ e prosseguir com a definição em outra linha.0. if(i<0||i>100) ERRO.n). macros. Procure explorá-las para conhecer todo os seus potenciais.. o arquivo conio. #undef GRANDE ENORME SOMA(x.8.altura) AREA_TRIANG(base.14159 (PI*(raio)*(raio)) ((base)*(altura)) ((base)*(altura)/2) Grave o programa acima como areas.h” /* para arquivos locais ou localizados na biblioteca do compilador */ O uso consciente das diretivas #define e #include podem melhorar muito o desempenho e a organização do seus projetos de software. basta incluir nos seus outros programas uma das diretivas abaixo: #include <areas. Exemplo: #define #define #define #define PI AREA_CIRCULO(raio) AREA_RETANG(base. Outra vantagem do uso de macros é a não necessidade de especificar o tipo do dado. Marcelo Ricardo Stemmer 80 .h contém o protótipo das funções getch() e getche() e é por esse motivo incluído nos programas que fazem uso destas funções. Geralmente.8. 4. #undef #define . somente o nome do macro deve constar na diretiva #undef.altura) 3. Os arquivos de inclusão são textos escritos em caracteres ASCII normais. pois o código do macro será duplicado cada vez que o macro for chamado. 4.. criados geralmente para incorporar definições de constantes. cabeçalho).Informática Industrial I DAS/UFSC será aumentado.h” (de header... #undef .4 Diretiva #include A diretiva #include causa a inclusão de uma código fonte em outro. para remover um macro.. Por exemplo. No instante em que você precisar reescrevê-las para a utilização em seu programa use a diretiva #include para inserir este arquivo no seu código fonte... #undef .h> /* para arquivos localizados na biblioteca do compilador */ #include “areas. protótipos de funções.3 Diretiva #undef A diretiva #undef remove a mais recente definição criada com #define. Não deve ser incluída a lista de argumento. definições de tipos de dados complexos e declarações de variáveis externas. Aqui está o exemplo de sua utilidade: suponha que você escreveu várias fórmulas matemáticas para calcular áreas de diversas figuras. Você pode colocar estas fórmulas em macros em um programa separado.y) GRANDE ENORME 10 ENORME ENORME SOMA 3 8 ((x)+(y)) /* cancela a definição de GRANDE /* redefine ENORME para o valor 10 /* ENORME volta a valer 8 /* cancela a definição de ENORME /* cancela a macro SOMA */ */ */ */ */ Observe que. os arquivos de inclusão têm um nome terminado com o sufixo “. Quando você quiser utilizar estas macros.h.. #define #define #define . . mas só se permite um única diretiva #else. A diretiva #else é opcional e. o programa poderá manipular o número máximo de registros. as diretivas: #if. #ifndef.8. #endif Para testar constantes definidas com #define que não tenham valor nenhum. erro2).6 Operador defined Um alternativa ao uso de #ifdef e #ifndef é o operador defined. erro1). #ifdef VERSAO_DEMO #define NUM_REC 20 #include “progdemo. Abaixo apresentamos um exemplo onde definimos o valor de uma constante com #define e depois a utilizamos para fazer uma compilação condicional : #define DEBUG 1 . podemos utilizar #ifdef e #ifndef. #if DEBUG == 1 printf(“\nERRO = ”.. Por exemplo: #define VERSAO_DEMO . Por exemplo: #ifndef WINDOWS #define VERSAO “\nVersão DOS” #else #define VERSAO “\nVersão Windows” #endif 4. #if defined(UNIX) && !defined(INTEL_486) .5 Compilação Condicional O pré-processador oferece diretivas que permitem a compilação condicional de um programa..Informática Industrial I DAS/UFSC 4. se estiver presente. #elif. A diretiva #ifndef verifica a não-definição da constante. Entre #if e #endif pode ser colocado qualquer número de #elif. #elif DEBUG == 2 printf(“\nERRO = ”.h” else #define NUM_REC MAXINT #include “program.”)..h” #endif O último exemplo mostra como um único programa-fonte pode gerar dois executáveis diferentes: se a diretiva que define VERSAO_DEMO for inserida. o executável poderá manipular somente 20 registros e estará criada a versão demo de seu programa. São elas. #ifdef.8. Caso esta diretiva não esteja presente.. deve ser a última anterior a #endif. #else e #endif Cada diretiva #if deve terminar pela diretiva #endif. Elas facilitam o desenvolvimento do programa e a escrita de códigos com maior portabilidade de uma máquina para outra ou de um ambiente a outro. #else printf(“\nERRO não documentado.. #endif Marcelo Ricardo Stemmer 81 . 9 Matrizes Uma matriz é um tipo de dado usado para representar uma certa quantidade de variáveis de valores homogêneos. Matriz é o tipo de dado oferecido por C para este propósito.h” 8.8 diretiva #pragma • • #pragma inline . e o valor 0 se for par.7 Diretiva #error A diretiva #error provoca uma mensagem de erro do compilador em tempo de compilação. Escreva uma macro que tenha valor 1 se o seu argumento for um caractere entre ‘0’ e ‘9’.4.indica ao compilador C para ignorar "warnings" (avisos) 4. Você certamente precisará de uma maneira conveniente para referenciar tais coleções de dados similares. 8. Utilize a mesma idéia que o programa anterior. coloque o texto de cada língua em um header diferente. 8. Caso nenhuma das duas for definidas. escreva o calendário de um ano qualquer dado pelo usuário em três línguas diferentes: alemão. Escreva uma macro que tenha valor 1 se o seu argumento for um número ímpar.Informática Industrial I DAS/UFSC 4. Escreva um programa que solicite ao usuário uma letra e retorne o número equivalente desta letra na tabela ASCII em decima e hexadecimal. Escreva uma macro que converta um dígito ASCII entre ‘0’ e ‘9’ a um valor numérico entre 0 e 9. inglês e português.8. gere um erro de compilação.9 Exercícios 8.1. aloca memória para armazenar 5 inteiros e anuncia que notas é uma matriz de 5 membros ou “elementos”. onde cada variável é diferenciada através de um número chamado “subscrito” ou “índice”.2.8.4. Imagine que você esteja precisando armazenar e manipular as notas de um ano inteiro de um conjunto de 40 alunos. Escreva uma macro que encontre o maior entre seus três argumentos.3. os textos em português ficam definidos em “progport.5.h” e os textos em inglês em “progingl. 8. por exemplo uma para português e outra para inglês.8. 8. Utilize a compilação condicional para gerar um programa com interface para diferentes línguas.indica ao compilador C a presença de código Assembly no arquivo. Marcelo Ricardo Stemmer 82 . e 0 se não for. A declaração: int notas[5]. #pragma warn . #if TAMANHO > TAMANHO1 #error “Tamanho incompatível” #endif 4. Um matriz é uma série de variáveis do mesmo tipo referenciadas por um único nome.6. Faça com que o programa do exercício 7. 4. Dica. Colchetes são usados para conter o subscrito. Por exemplo. onde indica o seu tamanho. O que diferencia a declaração de uma matriz da declaração de qualquer outra variável é a parte que segue o nome. i++) { printf("Digite a nota do aluno %d: ". um seguido do outro. Por exemplo: int notas[5]. ¬as[i]).". soma/NUM_ALUNOS). /* lendo os dados da matriz */ printf("Media das notas: %d. Por definição uma matriz é composta por elementos de um único tipo. . que indica ao compilador o tamanho da matriz. Os elementos da matriz são guardados numa seqüência contínua de memória. isto é. /* Exemplo de matrizes /* média das notas de 5 alunos #include #define <stdio. os pares de colchetes [ e ] que envolvem um número inteiro. após a definição convencional do tipo de variável. como quaisquer outras variáveis.9. for(i=0. o elemento referenciado pelo número 2 Marcelo Ricardo Stemmer 83 . Assim. para que o compilador conheça o tipo de matriz e reserve espaço de memória suficiente para armazená-la. O acesso aos elementos da matriz é feito através do número entre colchetes seguindo o nome da matriz. isto é. este número especifica a posição do elemento na matriz. A dimensão da matriz vai depender de quantos pares de colchetes a declaração da matriz tiver. Os elementos da matriz são sempre numerados por índices iniciados por 0 (zero).1 Sintaxe de Matrizes As dimensões são definidas entre colchetes. Quando referenciamos um elemento da matriz. i<NUM_ALUNOS. Em C.h> NUM_ALUNOS */ */ 5 void main() { int notas[NUM_ALUNOS]. /* declaração de uma matriz unidimensional = vetor */ unsigned float tabela[3][2]. for(i=0. <Tipo> <nome> [<dimensão1>] [<dimensão2>] .. /* matriz tridimensional */ Analisando-se a primeira declaração: a palavra int declara que todo elemento da matriz é do tipo int. soma.Informática Industrial I DAS/UFSC Vamos agora fazer um programa que calcula a média das notas da prova do mês de Junho de 5 alunos. scanf("%d". } 4. /* atribuindo valores a matriz */ } soma = 0. i). i++) soma = soma + notas[i]. /* matriz bidimensional */ char cubo[3][4][6].. notas é o nome dado a matriz e [5] indica que a nossa matriz terá 5 elementos do tipo “int”. /* Declaração de matrizes */ int i. Observe que este número tem um significado diferente quando referencia um elemento da matriz e na declaração da matriz. matrizes precisam ser declaradas. i<NUM_ALUNOS. } } A instrução que inicializa a matriz é: static int tab[] = {50. 10. Isto acarretará resultados imprevisíveis e nenhuma mensagem de erro do compilador avisará o que está ocorrendo. 4. valor %= tab[d]. quant. Assim a solução é não permitir que o usuário digite dados para elementos da matriz acima do limite. Você pode tratar este elemento como um variável simples.h> LIM */ */ 5 void main() { int d. 25.2 Inicializando Matrizes Em C a inicialização de uma matriz é feita em tempo de compilação. &valor). valor. Atenção: A linguagem C não realiza verificação de limites em matrizes. O programa a seguir exemplifica a inicialização de uma matriz: /* exemplo de inicialização de matrizes /* programa que produz troco #include #define <stdio. por isto nada impede que você vá além do fim da matriz. Como programador você tem a responsabilidade de providenciar a verificação dos limites. quant). 10. Lembre-se de que a inicialização de uma variável é feita na instrução de sua declaração e é uma maneira de especificarmos valores iniciais pré-fixados. 1}.Informática Industrial I DAS/UFSC notas[2] não é o segundo elemento da matriz mas sim o terceiro. como uma variável inteira qualquer. for(d=0. Como proceder caso você não conheça a quantidade de termos que você precisa para a sua matriz? Aplique a idéia apresentada no programa exemplo acima. printf("Digite o valor em centavos: "). O acesso com notas[i] pode ser tanto usado para ler ou escrever um dado na matriz. scanf("%d". tab[d]. uma unidade menor que o tamanho da matriz. Matrizes da classe auto não podem ser inicializadas. 5. com a diretiva: #define NUM_ALUNOS 5 para alocar um número maior de termos. 1}. Assim o último elemento da matriz possui um índice. Marcelo Ricardo Stemmer 84 .9. 25. de forma a possuir espaço suficiente alocado para conter todos os possíveis termos da matriz. sempre que necessário. Matrizes das classes extern e static podem ser inicializadas. static int tab[] = {50. no caso de notas[i]. d++) { quant = valor/tab[d]. d<LIM. printf("Moedas de %d centavos = %2d\n". então atribuirá valores a outros dados ou até mesmo a uma parte do código do programa. 5. pois a numeração começa em 0. Se você transpuser o fim da matriz durante uma operação de atribuição. 1} Da mesma maneira se aplica para matrizes de três ou mais dimensões: int tresd[3][2][4] = { { {1. {0. 3} . As classes de variáveis com esta característica são extern e static. { {7. tab[0] = 50. tab[2] é 10 e assim por diante. 1. Assim. A matriz de fora tem três elementos. 1. 1} }. 6. 6. 1. os elementos (matrizes) são colocados entre as chaves depois do sinal de igual e separados por vírgulas. Se há menos inicializadores que a dimensão especificada. pois é o segundo de duas matrizes de uma dimensão. 1. 9. 0. Então. a função percorre todos os itens restantes da lista. 0}.9. pois é o primeiro elemento da matriz de uma dimensão. comparando cada um com o primeiro item. O segundo índice é [1]. de list[1] a list[tam-1]. {5. {0. 2. Como exemplo segue abaixo uma matriz bidimensional: char tabela[3][5] { {0. 4} . isto é. O objetivo é colocar o menor item da lista nesta variável.3 Matrizes como Argumentos de Funções C permite passar um matriz como parâmetro para uma função. = 0. em C. Este é um método famoso de ordenação de elementos em uma matriz devido a sua simplicidade e eficiência. A seguir apresentamos o método de Ordenação Bolha como exemplo de passagem de matrizes como argumentos. A linguagem C permite matrizes de qualquer tipo. isto é. você deve criar uma variável que existirá durante toda a execução do programa. 4} } }. Como podemos acessar o único elemento igual a 0 na matriz do exemplo anterior? O primeiro índice é [2]. 6. Note que não foi necessária a declaração da dimensão da matriz. 3. Usamos o termo mais de uma dimensão para referência a matrizes em que os elementos são matrizes. então por exemplo: tabela[2] == {1. 0. Se em seu programa você deseja inicializar uma matriz. {1. { {7. Cada elemento da matriz tabela na verdade será outra matriz. list[0]. pois é o terceiro grupo de duas dimensões. É um erro ter-se mais inicializadores que o necessário. 0. esta deveria se maior ou igual a dimensão fornecida pelo colchetes. uma matriz de duas dimensões é uma matriz em que seus elementos são matrizes de uma dimensão. 1. 2} . temos que a primitiva abaixo é verdade: Tresd[2][1][0] == 0 4. cada um destes elementos é uma matriz de duas dimensões de dois elementos onde cada um dos elementos é uma matriz de uma dimensão de quatro números. incluindo matrizes de matrizes. 2. 0. Os valores são atribuídos na seqüência. 3. Na verdade. 8. 7. 3} }. A função começa considerando a primeira variável da matriz. tab[1] é 25. Por exemplo. os outros serão zero. O terceiro índice é [0]. Caso tivéssemos escrito explicitamente a dimensão da matriz. o termo duas dimensões não faz sentido pois todas as matrizes são de uma dimensão.Informática Industrial I DAS/UFSC A lista de valores é colocada entre chaves e os valores são separados por vírgulas. As matrizes de duas dimensões são inicializadas da mesma maneira que as de dimensão única. 9. {4. 8} }. Cada elemento é composto por chaves e seus elementos internos separados por vírgulas. Sempre que encontrarmos um item Marcelo Ricardo Stemmer 85 . 0}. 0. 1. 0. O processo continua até que a lista toda seja ordenada. E novamente são feitas as comparações e trocas. a endereço da matriz já está referenciado no seu nome. j < tam-1. eles são trocados. basta escrever o nome desta. i. } while(list[tam++] != 0). list[j] = temp. int temp. O operador & não pode ser aplicado a matriz para se obter o endereço desta. list[d]). onde o índice do elemento é escrito entre os colchetes. Quando desejamos referenciar um elemento da matriz devemos acessá-lo através do nome da matriz seguida de colchetes. for(j = 0. scanf("%d". tam=0. } } O único elemento novo no programa acima é a instrução: ordena(list. /* Ordena. pois. do { printf("Digite numero: "). é tomado o próximo item.h> #define TAMAX 30 void ordena(int list[]. i++) if(list[j] > list[i]) { temp = list[i]. A matriz foi passada como argumento da função quando escrevemos somente o seu nome como parâmetro da função. ordena matriz de inteiros */ void ordena(int list[]. int tam). ordena(list. Entretanto se desejamos referenciar a matriz inteira. --tam). d. i < tam. int tam) { int register j. Este item deverá conter o próximo menor item. for(d=0. Esta função tem dois argumentos: o primeiro é a matriz list e o segundo é a variável que contém o tamanho da matriz. j++) for(i = j + 1. sem colchetes. d++) printf("%d\n". Terminada esta operação. list[i] = list[j].Informática Industrial I DAS/UFSC menor. void main() { int list[TAMAX]. list[1]. O nome de uma matriz desacompanhada de colchetes representa o endereço de memória onde a matriz foi armazenada. &list[tam]). ela é uma chamada à função ordena() que ordena os elementos de uma matriz segundo o método bolha. a instrução abaixo seria inválida: Marcelo Ricardo Stemmer 86 .c /* ordena os valores da matriz */ */ #include <stdio. --tam). } /* ordena(). d<tam. Portanto. quanto ao número de peças vendidas por cada um. O primeiro índice da matriz indica o número de funcionários da loja e o segundo índice. utiliza-se diretamente os dados da matriz original através do endereço passado. portanto. Assim. /* declaração de matriz bidimensional*/ int i. i<FUNC. a função usa o endereço da matriz para acessar diretamente os elementos da própria matriz da função que chama. os endereços da matriz e do primeiro elemento serão equivalentes: list == &list[0].h> */ */ #define FUNC 4 /* numero de funcionários */ #define MES 3 /* numero de meses */ #define MAXBARRA 50 /* tamanho máximo da barra */ void grafico(int p[][MES]. Isto significa que as alterações que forem feitas na matriz pela função afetarão diretamente a matriz original. O operador & somente pode ser aplicado a um elemento da matriz. Como a área de memória ocupada por uma matriz começa através do primeiro termo armazenado nesta. /* declaração da função */ void main() { int pecas[FUNC][MES]. A seguir apresentamos um exemplo de passagem de uma matriz bidimensional como parâmetro de uma função. pois são formadas por diversas variáveis. for(i=0. Quando se passa o nome de uma matriz para uma função. i++) Marcelo Ricardo Stemmer 87 .Informática Industrial I DAS/UFSC &list. j. o número de meses a serem avaliados. sendo portanto irrelevante o número de funções que a acessem. Este método é conhecido como chamada por valor. Esta tipo de passagem de parâmetros é denominado passagem de parâmetros por referência ou por endereço. Assim. O programa exemplo avalia a eficiência de funcionários de uma loja. int nfunc). a função toma o valor contido nesta variável e o instala em uma nova variável e em nova posição de memória criada pela função. a instrução: int *ptr = &list[0].9. a função ordena() recebe um endereço de uma variável int e não um valor inteiro e deve declará-lo de acordo. as matrizes são consideradas um tipo de dado bastante grande. Entretanto. não se cria uma cópia dos dados desta mas sim. Desta forma. não são passados os valores contidos na matriz. 4. Portanto as alterações que forem feitas nos parâmetros da função não terão nenhum efeito nas variações usadas na chamada.4 Chamada Por Valor e Chamada Por Referência Quando um nome de uma simples variável é usado como argumento na chamada a uma função. /* Exemplo da matrizes bidimensionais /* histograma horizontal #include <stdio. a linguagem C determina ser mais eficiente existir uma única cópia da matriz na memória. Por causa disto. Portanto. somente o seu endereço de memória. O tipo : int [] indica um endereço de uma variável int. será válido e irá retornar o endereço da primeira variável da matriz. MEDIA\n--------------\n"). j<MES. j++) { printf("Numero de pecas vendidas pelo funcionario"). desenha um histograma */ void grafico(int p[][MES]. } else tam = 0. if(media[i]>0) { if((tam=(int)(((float)media[i])*MAXBARRA/max)) <= 0) tam = 1. j. i++) { media[i] = 0. &pecas[i][j]). for(i=0. tam>0. } max = 0. uma matriz com a primeira dimensão de qualquer valor pode ser passada para a função chamada. int nfunc) { int register i. i+1. Como não há verificação de limites. printf("\n\n\n\n FUNC . FUNC). i<nfunc. for(. a função multiplica o primeiro índice (2) pelo número de elementos da segunda dimensão (MES) e adiciona o segundo Marcelo Ricardo Stemmer 88 . j<MES. scanf("%d". visto que sempre passamos o seu endereço. } } O método de passagem do endereço da matriz para a função é idêntico ao da passagem de uma matriz de uma dimensão. media[i]). Mas uma função que recebe uma matriz bidimensional deverá ser informada do comprimento da segunda dimensão para saber como esta matriz está organizada na memória e assim poder operar com declarações do tipo: pecas[2][1] pois. tam = 0. i< nfunc. i++) { printf("%5d . for(i=0. i++) if(media[i]>max) max = media[i]. j+1). int max. } /* grafico(). FUNC). for(j=0. i+1.i<FUNC. j++) media[i] += p[i][j]. '>'). grafico(pecas.Informática Industrial I DAS/UFSC for(j=0.%5d : ". printf("\n"). printf("%d no mes %d: ". for(i = 0. não importando quantas dimensões tem a matriz. } grafico(pecas. media[i] /= MES. para encontrar a posição na memória onde pecas[2][1] está guardada. media[FUNC]. --tam) printf("%c". Esta estrutura será vista somente nos capítulos posteriores.5. onde fica claro que se você digitar uma frase com um número maior de caracteres do que a matriz alocada. para finalmente somar ao endereço da matriz (pecas).5. armazenando estes caracteres nesta matriz e adicionando automaticamente o caracter delimitador de strings ’\0’ no final da matriz. também chamado de NULL. tem o valor zero decimal (tabela ASCII). Por esta razão é que C não fornece uma estrutura amigável para a manipulação de string comparada com outras linguagens como Pascal. onde cada um ocupa um byte de memória. Vários exemplos de strings constantes estão presentes ao longo deste texto. Observe que o caracter ‘\0’. Somente com o advento da orientação a objetos (C++) é que C veio a fornecer uma estrutura amigável e flexível para tratar strings. Caso o comprimento da segunda matriz não seja conhecido. apresentaremos strings na sua forma básica em C. entretanto o tipo empregado é o tipo char.2 String Variáveis Um das maneiras de receber uma string do teclado é através da função scanf() pelo formato %s. 4. Desta forma. /* declara uma string com 15 caracteres */ Marcelo Ricardo Stemmer 89 . Depois ela armazena a string na matriz fornecida. Abaixo apresentamos um exemplo. Isto se deve ao fato de scanf() não testar a dimensão de matriz e simplesmente adquirir uma seqüência de caracteres até encontrar um caracter [enter]. string é uma série de caracteres. O importante é lembrar que o compilador sempre adiciona o caracter ‘\0’ a strings constantes antes de armazená-las na forma de matriz para poder marcar o final da matriz. Em outras palavras. por exemplo. será impossível saber onde estão os valores. armazenados em seqüência e terminados por um byte de valor zero (‘\0’). lê uma string do teclado e imprime */ #include <stdio. que tem valor 48 decimal (tabela ASCII). adiciona o caracter ‘\0’ e armazena em uma matriz de caracteres. espaço simples ou tabulação.5 Strings C não possui um tipo de dado especial para tratar strings. e não se trata do caracter ‘0’. 4. A terminação ‘\0’ é importante. tais como : printf(“Bom Dia!!!!”).h> void main() { char nome[15].9. String é uma matriz tipo de char que armazena um texto formado de caracteres e sempre terminado pelo caractere zero (‘\0’). O compilador aloca uma matriz com tamanho uma (1) unidade maior que o número de caracteres inseridos na string constante. /* string 1.9. Perceba que o endereço da matriz e passado escrevendo-se somente o nome da matriz.Informática Industrial I DAS/UFSC índice (1). Aqui. A função scanf() lê uma string até você apertar a tecla [enter]. pois é a única maneira que as funções possuem para poder reconhecer onde é o fim da string.9. sem testar a dimensão da matriz. (char[15]) um erro de memória irá ocorrer. Cada caracter é um elemento independente da matriz e pode ser acessado por meio de um índice. A definição de uma string segue o mesmo formato da definição de matrizes. caracterizado por uma seqüência de caracteres armazenados terminados por ‘\0’ (que possui o valor 0 na tabela ASCII) em uma matriz.1 Strings Constantes Qualquer seqüência de caracteres delimitadas por aspas duplas é considerada pelo compilador como uma string constante. 4. uma das aplicações mais importante de matrizes em C é justamente a criação do tipo string. strcmp() e strcpy(). ‘i’. ‘\0’}. inicializamos termo por termo como a seguir: char text[] = {‘B’. o compilador faz isto automaticamente para você. printf("Saudacoes.Informática Industrial I DAS/UFSC printf("Digite seu nome: "). Em C. Já na forma simples. junta uma string ao final de outra. Após a impressão. Veremos aqui as 4 funções principais: strlen(). Note que estas funções exigem que o caracter ‘\0’ esteja delimitando o final da string. isto é. Chamando a função puts() e passandose o nome da matriz de caracteres terminada por ‘\0’ como parâmetro. como parâmetro. ‘a’. Isto se deve ao fato de que scanf() utiliza qualquer espaço. A função strcat() concatena duas strings. a função gets() se aplica de forma mais eficiente para a aquisição de strings. quebra de linha ou tabulação para determinar o fim da leitura de uma string. ‘o’. ‘d’. descontando assim o caracter de final da string ‘\0’.9. Desta forma podemos utilizar gets() para ler strings com espaços e tabulações.5. o que impossibilita a sua aplicação para escrever duas strings na mesma linha.3 Funções para Manipulação de Strings Em C existem várias funções para manipular matrizes e tentar tornar a vida do programador um pouco mais fácil.". Ela toma dois endereços de strings como argumento e copia a segunda string no final da primeira e esta combinação gera uma nova primeira string. terminada com ‘\0’. ou seja. temos um exemplo: char nome[] = “Alexandre Orth”. A função gets() adquire uma string até ser pressionada a tecla [enter]. strcat(). temos que adicionar explicitamente o caracter ‘\0’ para determinar o fim da matriz. 4. ou seja. que foi apresentada no exemplo anterior. ‘!’. a função scanf() irá eliminar o segundo nome. O formato de impressão de strings com prinf() nós já conhecemos. teremos a string impressa na tela (saída padrão) até encontrar o caracter ‘\0’. na inicialização formal. ela retorna o tamanho da matriz que armazena a string menos um. Entretanto. ‘m’. a inicialização formal de strings ocorre da mesma maneira que para uma matriz. %s. basta escrever o parâmetro %s no meio da string de formatação de printf() e posteriormente passar o nome da matriz de caracteres. Para imprimir strings utilizamos as duas funções principais printf() e puts(). nome). Sintaxe de strlen(): strlen(string). Note que. C fornece ainda uma maneira simples. A função strlen() aceita um endereço de string como argumento e retorna o tamanho da string armazenada a partir deste endereço até um caractere antes de ‘0’. scanf("%s". puts(nome). nome). caracteres alocados localizados após o delimitador de final de string ‘\0’) suficientes para armazenar a segunda string. a matriz da primeira string deve conter caracteres livres (ou seja. Abaixo . Neste caso. } Se você escrever Pedro Silva no programa acima. puts() executa uma quebra de linha automaticamente [enter]. A segunda string não é alterada. ‘ ’. adicionando o caracter ‘\0’ para especificar o fim da string e armazená-la em uma matriz. Puts() tem uma sintaxe bem simples também. A função Marcelo Ricardo Stemmer 90 . A função strcmp() compara duas strings e retorna: < 0 0 > 0 : : : no caso da string 1 < que a string 2 no caso da string 1 = a string 2 no caso da string 1 > que a string2 Neste contexto. void main() { char string[81]. posicao\n"). adquira os valores dos termos que compõem a matriz. int posicao. puts(string). int n). [enter]. Crie um programa para calcular a matriz transposta de uma dada matriz. que a string1 deve conter espaço suficiente para armazenar os dados da string2. gets(string).h> void strdel(char str[]. Note. apaga caractere de uma string */ #include <stdio. solicitando ao usuário que forneça estes dados. } /* strdel(). Neste exemplo vamos implementar a função strdel() que move. string2). Crie uma função para inicializar a matriz com zero. Abaixo vamos mostrar um exemplo que apagar um caracter do interior de uma string.9. /* delete. um espaço à esquerda. Marcelo Ricardo Stemmer 91 . “menor que” (<) ou “maior que” (>) indica que. posicao). apaga um caractere de uma string */ void strdel(char str[].6 Exercícios 9. Aloque uma memória para uma matriz bidimensional com dimensão máxima de 10x10. A função strcpy() simplesmente copia uma string para outra. se você colocar string1 e string2 em ordem alfabética. considerando a dimensão máxima permitida. Sintaxe da função strcpy(): strcpy(string1. string2). string2). strdel(string. &str[n+1]). calcule a transporta da matriz e escreva na tela o resultado final da matriz.Informática Industrial I DAS/UFSC strcat() não verifica se a segunda string cabe no espaço livre da primeira. Por fim. &posicao). Sintaxe de strcmp(): strcmp(string1. scanf("%d". o que aparecerá primeiro será menor que o outro. } 4. int n) { strcpy(&str[n]. Depois. todos os caracteres que estão a direita do caracter sendo apagado. Depois questione o usuário para sob a dimensão da matriz que ele deseja calcular a transposta. Sintaxe de strcat(): strcat(string1. printf("Digite string.1. 4. Escreva uma função que localize um caracter em uma string e depois o substitua por outro. Armazene o valor de cada compromisso através de uma tabela de strings. 9.6. considerando o tipo de dado da matriz. Escreva uma função que insira um determinado character em uma determinada posição de uma string. /* novo tipo */ real_array x. com pivotamento. y. Escreva uma função que indique quantas vezes aparece um determinado caracter em uma dada string. float. Inicialize a tabela com valor 0.2. Exemplo da definição de um novo tipo de dado: typedef double real_array [10].10 Tipos Especiais de Dados Em C podemos definir novos tipos de dados. int. 9. que a matriz inicial tem tamanho 10x10 e o tamanho utilizado pelo usuário. 4. tabulações ou nova linha [enter] de uma dada string.1 Typedef Typedef nos apresenta a primeira forma de criar um novo tipo de dado.1 e crie um programa que calcule a decomposição LDU de uma matriz. 9.2 para criar uma tabela com os seus horários ocupados e compromissos na semana.Informática Industrial I DAS/UFSC 9. Os novos tipos são sempre compostos de uma ou mais variáveis básicas agrupadas de alguma maneira especial . compostos pelos tipos de dados já pré-existentes (char. Ou seja.3. A decomposição LDU é uma decomposição famosa de matrizes aplicada para calcular inversas de matrizes e resolver problemas de equações lineares. Crie uma função que calcule este dado comparando duas matrizes de dimensões quaisquer. Sintaxe: typedef <tipo> <definição>. Typedef permite a definição de novos tipos de variáveis.9.10. Por fim. Continue o programa anterior e agora calcule o tamanho de memória alocada para a matriz e que não está sendo utilizada. /* declara variáveis tipo real_array */ Marcelo Ricardo Stemmer 92 . Reflita sobre este problema. preferencialmente. 9.5.8. 9. Utilize o programa 9. e solicite ao usuário que forneça o seu horário. 4. adicionando complexidade aos tipos de dados já existentes. Escreva uma função que retire todos os caracteres brancos. apresente na tela o resultado obtido.7. Com a finalidade de tornar a vida do programador mais fácil e permitir que este crie novos tipos de dados. Refaça o seu exercício 6. double e matrizes destes tipos). 9. Escreva um programa que converta todas os caracteres minúsculos de uma string para o correspondente caracter maiúsculo. 9. quantos bytes de memória o computador alocou para a matriz e quantos bytes de memória o usuário realmente utilizou. dia2 = terca + 3. Abaixo apresentamos exemplos da aplicação de tipos enumerados e de suas definições: /* Exemplo de tipos enumerados */ /* definição de novos tipos de dados */ enum dias { segunda. Marcelo Ricardo Stemmer 93 . /* false = 0 */ true /* true = 1 */ }. enum cores { verde = 1. 1. enum boolean { false. atribuímos um nome significativo para representá-lo. /* atribui: quarta = 2. */ sexta. preto.10. A vantagem é que usamos estes nomes no lugar de números. if (dia2 == sabado) b1 = true. azul = 2. como em nosso programa. representam um vetor de valores reais (double) com capacidade para armazenar 10 dados deste tipo. recebe valor anterior + 1 = 3 */ branco = 7 }. */ quinta. /* atribui: segunda = 0. A sintaxe fica clara no exemplo acima. ambas ‘x’ e ‘y’ foram declaradas como sendo do tipo ‘real-array’ e por isso. etc. /* declara variável "dias" do tipo enum */ enum boolean b1.Informática Industrial I DAS/UFSC No exemplo acima. A palavra enum enumera a lista de nomes automaticamente. */ sabado. 2. */ domingo /* atribui: domingo = 6. o compilador atribuirá o próximo valor inteiro aos que não tiverem valor.2 Enumerados (Enum) Permitem atribuir valores inteiros seqüenciais à constantes. /* atribui: sexta = 4.). void main() { enum dias dia1. a partir do primeiro valor fornecido. Tipos enumerados são usados quando conhecemos o conjunto de valores que uma variável pode assumir. para cada um dos valores do conjunto. /* como não foi dado valor. Se fornecemos um valor a alguns nomes e não a outros. o que torna o programa mais claro. /* atribui: terca = 1. */ quarta. dando-lhes números em seqüência (0. 4. A variável deste tipo é sempre int e. /* atribui: quinta = 3. /* declara variável do tipo enum boolean */ dia1 = terca. dia2. } /* dia2 = sexta */ A palavra enum define um conjunto de nomes com valores permitidos para esse tipo e enumera esses nomes a partir de zero (default) ou. /* atribui: sabado = 5. */ }. */ terca. Observe que nas matrizes (arrays). /* Declaração de variáveis/ Pessoa P1. Abaixo apresentamos as duas sintaxe que podem ser empregadas para a definição de estruturas e para a declaração de variáveis deste tipo: Sintaxe : struct <nome> /* Definição */ { <tipo> <nome campo>. Definir um tipo de dado significa informar ao compilador o seu nome.3 Estruturas (Struct) Structs permitem definir estruturas complexas de dados. float Peso. Tipos enumerados são tratados internamente como inteiros. 4. } P1. P2. todos os campos são do mesmo tipo. }[<variáveis deste tipo>]. int Idade. Uma vez criada a variável estrutura.*/ { <tipo> <nome campo>. .Informática Industrial I DAS/UFSC Um variável de tipo enumerado pode assumir qualquer valor listado em sua definição. Não há nenhuma reserva de memória. P3.Nome). o novo tipo existe e pode ser utilizado para criar variáveis de modo similar a qualquer tipo simples. } <nome tipo>. a forma da declaração de variáveis deve ser sempre explícita. Desta forma. } Pessoa. Por meio da palavra-chave struct definimos um novo tipo de dado.Idade = 41. entretanto. O operador ponto conecta o nome de uma variável estrutura a um membro desta. Já na segunda sintaxe. o seu tamanho em bytes e o formato em que ele deve ser armazenado e recuperado na memória. float Peso. Marcelo Ricardo Stemmer 94 typedef struct <nome> /* Def. com campos de tipos diferentes. Definir uma estrutura não cria nenhuma variável. criar elementos semelhantes a arrays. As structs permitem. Na primeira sintaxe. P1.10. Valores não listados na sua definição não podem ser assumidos por esta variável. portanto qualquer operação válida com inteiros é permitida com eles. Abaixo. mostramos no exemplo como podemos declarar um variável do tipo da estrutura “Dados_Pessoais” já na definição da estrutura (P1) e como podemos criar outras variáveis deste tipo ao longo do programa (P2 e P3). mas composta de elementos com tipos diferentes de dados. Exemplo : struct Dados_Pessoais { char Nome[81]. somente informa ao compilador as características de um novo tipo de dado. faz-se necessário a declaração de variáveis deste tipo. como mostrado no exemplo. int Idade. typedef struct Dados_Pessoais { char Nome [ 81]. seus membros podem ser acessados por meio do operador ponto. fornecemos exemplos de acesso as variáveis definidas por meio de estruturas: gets(P1. /* Declaração de variáveis/ <nome tipo> <nome variável>. A palavra struct indica que um novo tipo de dado está sendo definido e a palavra seguinte será o seu nome. /* Declaração de Variáveis */ struct Dados_Pessoais P2. /* Declaração de Variáveis */ struct <nome> <nome variável>. Após ter sido definido. /* livros. Por exemplo. A linguagem C trata os membros de uma estrutura como quaisquer outras variáveis simples. onde uma estrutura contém no seu interior como membro outra estrutura.h> /* para atof() e atoi() */ /* definição de tipos */ struct list { char titulo[30]. Isto cria o que chamamos tipos aninhados de estruturas. onde trataremos de uma matriz de estruturas que contém os dados necessários para representar um livro. Estruturas podem ser passadas para funções assim como qualquer outra variável.h> #include <stdlib. A forma de acesso aos membros da estrutura. Funções podem também retornar uma estrutura como o resultado do seu processamento.Peso = 75. A inicialização de estruturas é semelhante à inicialização de uma matriz. int regnum.6. Para tal. Uma variável estrutura pode ser atribuída através do operador igual (=) a outra variável do mesmo tipo: aniversario = natal. por exemplo. P1.Idade é o nome de uma variável do tipo int e pode ser utilizada em todo lugar onde possamos utilizar uma variável int. Certamente constatamos que esta é uma estupenda capacidade quando pensamos a respeito: todos os valores dos membros da estrutura estão realmente sendo atribuídos de uma única vez aos correspondentes membros da outra estrutura. char mes[10]. basta declarar o tipo de retorno de uma função como sendo um tipo declarado por uma struct. e estão definidas em stdlib. com matrizes. basta declarar o tipo da matriz como o tipo definido pela estrutura. Isto já não é possível. }. As funções atoi() e atof() apresentadas no exemplo abaixo servem para converter strings para um tipo inteiro ou float. Estruturas não permitem operações entre elas. “Dezembro”. Esta é uma forma de fazer com que uma função retorne mais de um parâmetro. int ano. Após definirmos um tipo de dado através de uma estrutura. Marcelo Ricardo Stemmer 95 . char autor[30]. A seguir apresentamos um exemplo envolvendo matrizes de estruturas. Podemos criar uma matriz para estruturas assim como criamos uma matriz de um tipo qualquer. “Julho”. 1994}. Veja um exemplo: struct data { int dia. 1998}. respectivamente. data aniversario = { 30.Informática Industrial I DAS/UFSC P3. data natal = { 25. Esta operação funciona assim como uma matriz bidimensional na verdade é uma matriz de matrizes unidimensionais. sendo declarada e utilizada da mesma forma. somente entre os seus membros. podemos incluir este tipo de dado como membro de uma outra estrutura. armazenadas na matriz fica clara no exemplo. mantém lista de livros na memória */ #include <stdio. i++) Marcelo Ricardo Stemmer 96 . gets(numstr). void listatotal(). } } } /* novonome().Informática Industrial I DAS/UFSC double }. printf("\n'l' para listar todos os livros: ").autor). preco. break. if(!n) printf("\nLista vazia. n+1). printf("\nDigite autor: "). default: puts("\nDigite somente opcoes validas!!!!"). adiciona um livro ao arquivo */ void novonome() { char numstr[81]. printf("\nRegistro %d. gets(numstr). printf("\nDigite o numero do livro (3 digitos): "). n++.preco = atof(numstr). } /* listatotal(). \nDigite titulo: ".titulo). gets(livro[n]. lista os dados de todos os livros */ void listatotal() { int i. void novonome(). /* converte string p/ int */ printf("\nDigite preco: "). livro[n]. i<n. gets(livro[n]. ch = getche(). livro[n]. /* declaração de variáveis e funções */ struct list livro[50]. else for(i=0. int n = 0. case 'l': listatotal(). switch(ch) { case 'e' : novonome().\n"). break. void main() { char ch.regnum = atoi(numstr). while(1) { printf("\nDigite 'e' para adicionar um livro"). 10. livro[i]. de forma semelhante a struct. /* um array de 8 bytes */ } unionvar. /*um double de 8 bytes */ int i[4]. void main() { unionvar. printf("\nTitulo: %s.\n". Sintaxe: union <nome> { <tipo> <campo1>.\n". union Oito_bytes { double x. Veja o teste realizado abaixo. Exemplo do emprego das uniões: typedef unsigned char byte. A função sizeof() resulta o tamanho em bytes ocupado por uma dada variável. vamos utilizar a função sizeof(). } } 4. onde apresentamos o valor em bytes ocupado por cada membro da união e o valor em bytes ocupado pela união inteira. \n".Informática Industrial I DAS/UFSC { printf("\nRegistro: %d. uma union utiliza um mesmo espaço de memória a ser compartilhado com um número de diferentes membros. printf("\nAutor: %s. pois a utilização irresponsável das uniões podem causar a perda de dados importantes do programa. Podemos verificar também que todos os membros da união ocupam a mesma posição da memória utilizando o operador & para obter a posição da memória onde estão armazenados os dados. unionvar. printf("\nPreco: %4.3f. Por isso. uma union é o meio pelo qual um pedaço de memória ora é tratado como uma variável de um certo tipo.\n". i+1). Entretanto. automaticamente é alocado espaço de memória suficiente para conter o seu maior membro. ora como outra variável de outro tipo.autor). /* sobreescreve valor anterior ! */ } Para verificar que o tamanho de uma variável union é igual ao tamanho do maior membro.titulo). }. /* um array com 4 inteiros = 8 bytes */ byte j[8].regnum). uniões são usadas para poupar memória e o seu uso não é recomendado a não ser em casos extremamente necessários. livro[i]. livro[i]. Quando você declara uma variável do tipo union.preco). : <tipo n> <campo n>.7. para agrupar um número de diferentes variáveis sob um único nome. enquanto uma struct aloca um espaço diferente de memória para cada membro. Em outras palavras.x = 2.4 Uniões A palavra union é usada.\n". Marcelo Ricardo Stemmer 97 . livro[i]. printf("\nNumero do registro: %3d.i[1] = 3. str). 1. mem: 50EF:0D66. } x. mem: 50EF:0D66. printf("Sizeof(x) = %d bytes. Sizeof(x) = 20 bytes. 1. } A saída do programa será como esperado: Sizeof(str[20]) = 20 bytes. Estas são úteis quando desejamos representar dados que ocupam somente um bit.\n". Sintaxe: struct <nome> { <tipo> <campo> : <comprimento em bits>. &(x.\n". /* declara variável Flags */ 98 . mostra o uso de sizeof() */ #include <stdio. mem: 50EF:0D66. 1. /* declara bitfield */ : : : : : : : : 1. 1. sizeof(x).sizeof(x. Sizeof(i) = 2 bytes. 4. float f.f). void main() { printf("Sizeof(str[20]) =%d bytes. sizeof(x. mem: 50EF:0D66. x. \tmem: %p. printf("Sizeof(i) = %d bytes. &(x)). 1. int i.\n". printf("Sizeof(f) = %d bytes. 1.h> union num { char str[20]. mem:%p.str). main( ) { struct Registro_Flags Marcelo Ricardo Stemmer Flags. Sizeof(f) = 4 bytes.i)). 1.f)). \tmem: %p. }.\n". \tmem: %p. Exemplo aplicando bitfields: #define ON 1 #define OFF 0 struct Registro_Flags { unsigend int Bit_1 unsigend int Bit_2 unsigend int Bit_3 unsigend int Bit_4 unsigend int Bit_5 unsigend int Bit_6 unsigend int Bit_7 unsigend int Bit_8 }. &(x.10. sizeof(x. // Cria a variavel do tipo union num.Informática Industrial I DAS/UFSC /* Sizeof().i).5 Bitfields Bitfields são um tipo especial de estrutura cujos campos tem comprimento especificado em bits. Utilize uma estrutura para os clientes e outra para as fitas. 4.4 Escreva um programa para cadastrar livros em uma biblioteca e fazer consultas a estes. o mês e o ano. a abreviação em letras.11. empregamos o endereço dos ponteiros como uma forma indireta de acessar e manipular o dado de uma variável. 10. uniões).6 Crie uma estrutura para descrever restaurantes.Bit_2 = OFF.7 Crie um programa que faça o controle de cadastro de usuários e controle de alocação para uma locadora de fitas de vídeo.11 Ponteiros e a Alocação Dinâmica de Memória No capítulo sobre tipos de dados.Bit_1 = ON. 10. Escreva um programa que solicite ao usuário o dia. os ponteiros são declarados da seguinte forma: <tipo> * <nome da variável> = <valor inicial>.2. Escreva também um tipo enumerado para associar um nome ou uma abreviação ao número do mês. A estrutura deve ser capaz de armazenar o nome do mês. 10.2 Declare uma matriz de 12 estruturas descritas na questão anterior e inicialize-a com os dados de um ano não-bissexto.6 utilizando as estruturas aqui desenvolvidas. *p = 10.10.1 Declaração de Ponteiros e o Acesso de Dados com Ponteiros C permite o uso de ponteiros para qualquer tipo de dado. float. Flags. Como havíamos visto anteriormente (4. Ponteiros são tipos especiais de dados que armazenam o endereço de memória onde uma variável normal armazena os seus dados. double.Informática Industrial I DAS/UFSC Flags. por isso *p e *r são do tipo float e que p e r são ponteiros para variáveis float. Lembrando. 4.1 Escreva uma estrutura para descrever um mês do ano. float *p. sendo este um dado típico de C (int.5 Refaça o programa do exercício 8. justificaremos por que este são intensivamente empregados na programação C e apresentaremos algumas de suas aplicações típicas. Marcelo Ricardo Stemmer 99 . mas o operador * indica que esta variável trata de um ponteiro. o número de dias e o número do mês. Crie uma matriz de estruturas e escreva um programa que utilize uma função para solicitar os dados de um elemento da matriz e outra para listar todos os dados. char) ou definido pelo programador (estruturas. Agora apresentaremos diversas aplicações de ponteiros. definimos o que era ponteiro. float *r = 0. A sintaxe basicamente é a mesma que a declaração de variáveis. Imprima o total de dias do ano até o dia digitado. 10. o preço médio e o tipo de comida. 10. Desta forma. Os membros devem armazenar o nome. o endereço. 10.7). } 4.6 Exercícios 10.3 Escreva uma função que recebe o número do mês como argumento e retorna o total de dias do ano até aquele mês. \t&py = %p\n". \t&px = %p\n\n".Informática Industrial I DAS/UFSC faz com que a variável endereçada por p tenha o seu valor alterado para 10. \t*py = %d. px. %p. Para mostrar o resultado de cada operação. y = 6.py = %u\n". if(px<py) printf("py . o valor armazenado na variável apontada e o endereço da variável que armazena o próprio ponteiro. py).h> void main() { int x = 5. printf("px = printf("py = px++. /* ponteiro inicializado com 0 */ printf("Endereco contigo incialmente em :\n"). *px. O operador & aplicado a uma variável normal retorna o valor do seu endereço. printf("py = printf("py } %p. &px = 4F97:2120 &py = 4F97:211C &px = 4F97:2120 &py = 4F97:211C px = 4F97:2128. py. \t*px = %d. &py). py-px). *px = 20375. p = &num. *py. printf("Cuidado ao usar ponteiros nao incializados como px!!!\n\n"). &px). * é um operador que faz o acesso a variável apontada por um ponteiro. *py. px = &x. printf("\tpx = %p \n\tpy = %p. px-py). \t*px = %d. ou seja.2 Operações com Ponteiros A linguagem C oferece 5 operações básicas que podem ser executadas em ponteiros.\n". /* p recebe o endereço de ‘num’ */ 4. %p. px. py = 4F97:212E. &px). py = &y. py = 4F97:2124. *py = 20351. else printf("px . \t&py = %p\n\n". py. *px = 5. *px. py – px = 3 Marcelo Ricardo Stemmer 100 . o programa imprimirá o valor do ponteiro (que é um endereço).11. \t&px = %p\n". int *px. px = %u\n". O próximo programa mostras estas possibilidades. %p. int *py = 0. px. *py = 6. podemos dizer então: int num = 15. py-px). /* operacoes com ponteiros */ #include <stdio. \t*py = %d. Resultado do programa: Endereço contido inicialmente em: px = 21CD:FFFF py = 0000:0000 Cuidado ao utilizar ponteiros não inicializados como px!!!! px – py = 1 px = 4F97:2126. &py).px = %u\n". printf("px = py = px + 3. o computador executará esta operação sem problema. Esta diferença será expressa na unidade tipo apontado. pois a variável inteira ocupa 2 bytes. se px é um ponteiro para um inteiro e px contém o endereço 0x3006. Novamente. o programa não executaria esta operação pelo fato do ponteiro conter um endereço inválido ‘0’. ou seja. • O operador & junto ao nome do ponteiro retorna o endereço onde o ponteiro está armazenado. os ponteiros variáveis têm um endereço e um valor. O operador (*) aplicado na frente do nome do ponteiro. Após a execução da instrução: px++. No programa acima. tenha cuidado na manipulação de ponteiros para não acessar regiões inválidas de memória ou ocupadas por outros programas. Inicialize sempre os seus ponteiros com o valor zero ou ‘NULL’. o ponteiro px conterá o valor 0x3008 e não 0x3007. Entretanto. tentássemos acessar o valor da variável apontada pelo ponteiro ‘py’. o programa exemplo acima declara as variáveis inteiras ‘x’ e ‘y’. pois o endereço está válido. Em resumo: • O nome do ponteiro retorna o endereço para o qual ele aponta.px terá valor 1 quando px e py são ponteiros para int. Podemos incrementar um ponteiro através de adição regular ou pelo operador de incremento. apresentamos esta idéia de forma clara. Você pode adicionar ou subtrair de e para ponteiros. Outro cuidado a se tomar é quanto ao tipo apontado pelo operandos. se py tem valor 0x4008 e px o valor 0x4006. <=.Informática Industrial I DAS/UFSC Primeiramente. Cada vez que incrementamos px ele apontará para o próximo tipo apontado. Testes relacionais com >=. Se Marcelo Ricardo Stemmer 101 . se tentarmos acessar o valor da variável apontada por ‘px’. > e < são aceitos entre ponteiros somente quando os dois operandos são ponteiros. então. Incrementar um ponteiro acarreta a movimentação do mesmo para o próximo tipo apontado. fará com que py aponte para o terceiro elemento do tipo apontado após px. O mesmo é verdadeiro para decremento. • O operador * junto ao nome do ponteiro retorna o conteúdo da variável apontada. Caso. Em seguida. Se px tem valor 0x3006 depois da instrução: px--. retornará o valor da variável apontada por este ponteiro. depois de executada a instrução acima. a expressão py . Para mostrar a importância da inicialização de ponteiros. declarando dois ponteiros para inteiros também. o próximo inteiro. resolvemos mostrar na tela o valor inicial destes. Você pode encontrar a diferença entre dois ponteiros. O operador (&) retorna a posição de memória onde o ponteiro está localizado. Se px tem valor 0x3000. Note que um ponteiro foi inicializado com ‘0’ e o outro não. Por exemplo. ele terá valor 0x3004. atribuímos um valor válidos aos ponteiros utilizando o operador (&) para obter o endereço das variáveis ‘x’ e ‘y’. A instrução: py = px + 3. Como todas as variáveis. e assim poderemos cometer um erro gravíssimo acessando áreas de memórias inadequadas ou proibidas. py terá o valor 0x3006. mostrando na tela estes valores para os dois respectivos ponteiros. No exemplo a seguir mostramos como ponteiros podem ser usados como parâmetros da função. só poderíamos efetuar esta operação utilizando-se uma estrutura para conter x e y. matrizes. &y).Informática Industrial I DAS/UFSC você comparar ponteiros que apontam para variáveis de tipo diferentes. Estes endereços devem ser armazenados em variáveis temporárias da função chamada para permitir posteriormente o seu acesso.) é mais fácil e mais rápido acessar estes dados indiretamente através de um ponteiro do que realizar uma cópia destes para que a função possa utilizar o valor copiado. altera dois numeros da funcao que chama*/ void altera(int *px. Variáveis ponteiros podem ser testadas quanto à igualdade (==) ou desigualdade (!=) onde os dois operandos são ponteiros (px == py) ou um dos operandos NULL (px != NULL ou px != 0). • A passagem de parâmetro com ponteiros geralmente é mais rápida e eficiente do que com o próprio dado. void main() { int x = 0. esta passe endereços usando operadores de endereços (&). ou Marcelo Ricardo Stemmer 102 . 4. int *py) { if(px != 0) *px = 3. que o objetivo da função é prover modificações nas duas variáveis x e y... int *). . y = 0.3 Funções & Ponteiros Um das maneiras mais importantes para passar argumentos para uma função ou para que a função retorne um resultado é através de ponteiros. Numa forma simples. /* testa funca que altera dois valores */ #include <stdio. printf("O primeiro e %d.11. Para tal. basta que em vez da função chamadora passar valores para a função chamada. • Podemos utilizar ponteiros de estruturas complexas ou matrizes como forma de fazer com que funções retornem mais de um valor como resultado. • para tipos de dados complexos ou de grande dimensão (estruturas. você obterá resultados sem sentido. } Note. podendo efetuar modificações nestas variáveis. y).".h> void altera(int *. altera(&x. haja visto que o compilador não faz uma cópia deste dado e um ponteiro necessita somente de 4 bytes para armazenar o seu valor. } /* altera(). x. if(py != 0) *py = 5. Estes endereços são de variáveis da função chamadora onde queremos que a função coloque os novos valores. o segundo e %d. Ponteiros são empregados em funções principalmente quando necessitamos de umas das seguintes características: • ponteiros permitem que uma função tenha acesso direto as variáveis da função chamadora. O compilador transforma matrizes em ponteiros quando compila. O valor do endereço das variáveis foi obtido com o operador &. Isto serve para que a função verifique se o valor de endereço recebido é válido. 2 floats se a matriz for float e assim por diante. ou seja. mas C trata matrizes como se fossem ponteiros. o nome de uma matriz é um ponteiro constante.11. Outro aspecto importante é o teste efetuado antes de utilizar a o ponteiro recebido como parâmetro: if(px != 0) *px = 3. pode gerar um ponteiro inválido e o acesso a área de memória representada por este ponteiro pode causar um erro fatal no seu programa. pois a arquitetura do microcomputador entende ponteiros e não matrizes. Entretanto. A função necessitou apenas da declaração de um tipo ponteiro em seu cabeçalho para estar apta a receber endereços de variáveis como um de seus parâmetros. Na forma convencional por matriz. 5. Na verdade.Informática Industrial I DAS/UFSC criando uma função para alterar cada parâmetro. 4. *(matriz + indice) == matriz[indice] Marcelo Ricardo Stemmer 103 . Este é um dos métodos para prever erros com ponteiros. fazemos isto através da instrução: table[2] mas a mesma instrução pode ser feita com ponteiros. Ponteiros podem ser usados não somente para que a função passe valores para o programa chamador. Ponteiros e matrizes são idênticos na maneira de acessar a memória. Uma vez conhecidos os endereços e os tipos das variáveis do programa chamador.4 Ponteiros & Matrizes Você não percebe. a expressão (table+2) não significa avançar 2 bytes além de table e sim 2 elementos da matriz: 2 inteiros se a matriz for inteira. O tipo matriz é na verdade uma forma mais amigável que C fornece para tratar um ponteiro que aponta para uma lista de variáveis do mesmo tipo. Qualquer operação que possa ser feita com índices de uma matriz pode ser feita com ponteiros. Se cada elemento da matriz é um inteiro (2 bytes). 8. Ou seja. Um ponteiro variável é um endereço onde é armazenado um outro endereço. Suponha que declaramos uma matriz qualquer : int table = {10. 1. Tome muito cuidado com a manipulação de ponteiros. passando-se o endereço das variáveis x e y permitimos a função chamada que altera-se diretamente os seus valores. então vão ser pulados 4 bytes do início do endereço da matriz para atingir o elemento de índice 2. um erro no programa ou em uma função do sistema operacional. 6} e queremos acessar o terceiro elemento da matriz. considerando que o nome do vetor é na verdade um ponteiro para o primeiro elemento do vetor: *(table+2) A expressão (table+2) resulta no endereço do elemento de índice 2 da matriz. mas também para que o programa chamador passe valores para a função. Em outras palavras. a função pode não somente colocar valores nestas variáveis como também tomar o valor já armazenado nelas. um ponteiro. O nome de uma matriz é um endereço. haja visto que notas é um ponteiro constante. soma/(i-1)). Vamos mostrar um exemplo para esclarecer estes conceitos: /* media de um numero arbitrario de notas */ /* exemplo de ponteiros */ #include <stdio. ou em notação de matriz. soma = 0. notas+i). scanf("%f". podemos utilizar as facilidades fornecidas pelos ponteiros para manipular strings também. Marcelo Ricardo Stemmer 104 .2f". } O operador de incremento ou decremento não pode ser aplicado a ponteiros constantes.11. int register i = 0. passando-se como parâmetro um ponteiro para o primeiro elemento da matriz e depois utilizando este ponteiro para acessar todos os elementos da matriz. char).0. 4. Abaixo mostramos um exemplo que ilustra este caso: /* procura um caractere em uma string */ #include <stdio. ptr = notas.h> #include <conio. Esta sintaxe funciona exatamente igual como se estivessemos passando um ponteiro de uma variável normal como parâmetro. void main() { char *ptr. atribuir a ele o endereço da matriz e depois incrementar o valor deste ponteiro: float * ptr = 0. o operador (++) incrementa em 4 bytes a cada operação.Informática Industrial I DAS/UFSC Existem duas maneiras de referenciar o endereço de um elemento da matriz: em notação de ponteiros. Podemos passar matrizes como parâmetros para funções. }while(*(notas+i++) > 0).h> char * procstr(char *. não podemos substituir o comando (notas + i++) por (notas++). ptr apontar para uma matriz do tipo float. Para fazer isto. Por exempo. Veja a secção anterior para verificar esta sintaxe. matriz+indice.h> #define LIM 40 void main() { float notas[LIM]. do { printf("Digite a nota do aluno %d: ". precisamos criar um ponteiro variável qualquer. &matriz[indice]. (notas + i++) == (ptr++) /* são equivalentes */ Como. if(*(notas+i) > 0) soma += *(notas+i). printf("Media das notas: %.5 Ponteiros & Strings Como strings são na verdade tratadas em C como matrizes simples de caracteres finalinazadas por ‘0’ (caracter ‘\0’). i). as inicializações abaixo são equivalentes: char * salute = “Saudacoes”.Informática Industrial I DAS/UFSC char ch. puts("Digite uma sentenca: "). O tipo (char *) é reconhecido em C como sendo um tipo string. O valor de um ponteiro constante não pode ser modificado. while((*l != c)&&(*l != '\0')) l++.\n". } char * procstr(char * l. char c) { if(l == 0) return 0. } Primeiramente. As duas formas provocam o mesmo efeito. Por exemplo. mas são diferentes: a primeira declara salute como um ponteiro variável e a segunda como um ponteiro constante. O programa utilizou a manipulação de ponteiros para localizar a posição de um caracter em uma string e fornecer a sua posição ao usuário. antes de acessarmos o valor deste ponteiro. um ponteiro para uma sequência de caracteres. lin[81]. Podemos criar em C matrizes de ponteiros para strings. são extremamente rápidas e otimizadas. gets(lin). “Gustavo”. if(*l != '\0') return l. Marcelo Ricardo Stemmer 105 . ch). fornecemos aqui um exemplo de função que retorna como resultado um ponteiro. testamos se este é um ponteiro válido para não cometer nenhum erro acessando uma área imprópria da memória. por exemplo. printf("Digite o caractere a ser procurado: "). Nenhum espaço a mais de memória será alocado neste caso.\n"). } else printf("\nCaractere nao existe. podemos faze-lo diretamente como sendo um ponterio. por isso. Note que. char salute[] = “Saudacoes”. “Nigel”. Por isso. A maioria das funções em C manipulam strings como ponteiros e. ptr-lin). já um ponteiro variável pode ter seu valor modificado. por um incremento (++). Em vez de declararmos uma string como uma tabela.\n". ch=getche(). lin). ou seja. ptr). Esta é uma das maneiras mais econômicas para alocar memória para uma matriz de strings sem desperdiçar memória. ptr = procstr(lin. a inicialização: static char * list[5] = { “Katarina”. Entretanto. printf("\nA string comeca no endereco %p. esta inicialização alocará memória somente para o correspondente número de caracteres da string passada mais um caracter ‘\0’ para delimitar a string. printf("E a posicao: %d". return 0. if(ptr) /* if(ptr != 0) */ { printf("Primeira ocorrencia do caractere: %p. “Airton” }. 22. Vamos analisar um exemplo de acesso duplamente indireto de dados derivados de uma matriz de duas dimensões. 48} }. 15. for(j=0. ponteiros que apontam para ponteiros.Informática Industrial I DAS/UFSC “Francisco”. suponha que desejásemos reordenar as strings da matriz acima.h> #define LIN 4 #define COL 5 void main() { static int tabela[LIN][COL] = { {13. 21}. k++) *(ptr + j*COL + k) += c. onde cada elemento conterá o valor de um ponteiro para uma lista de caracteres (string). 26. Se quizessemos fazer a mesma inialização utilizando uma matriz de vetores de caracteres. Como a string é de ponteiros. j<LIN.6 Ponteiros para Ponteiros A habilidade da linguagem C de tratar partes de matrizes como matrizes cria um novo tópico de C. uma das razões para se inicializar “strings” com ponteiros é a alocação mais eficiente de memória. 4. 19. Por exemplo.11. Para fazer isto. Desta forma. {40. Esta habilidade dá a C uma grande flexibilidade na criação e ordenação de dados complexos. } } Marcelo Ricardo Stemmer 106 . int * ptr = tabela. não precisamos remover as strings de sua posição e escrevê-las em outra matriz na ordem correta. *(*(tabela+j)+k)). basta alocar espaço para cada elemento de 2 bytes. j++) { for(k=0. Por isto. já que as strings se caracterizam por conter um comprimento diferentes de caracteres. k. 46. 24. enquanto que a sequência de carateres apontado por este ponteiro pode estar em qualquer posição de memória. 17. 35. {31. /* uso de ponteiros para ponteiros */ #include <stdio. 42. basta trocar de posição os ponteiros que apontam para as strings. 28}. for(j=0. j<LIN. 44. 37. 33. {20. k++) printf("%d ". int j. Reordenando os ponteiros. k<COL. 39}. Uma outra razão é a de obter maior flexibilidade para manipular matrizes de strings. Vai alocar uma matriz com 5 elementos. o espaço de memória necessário para alocar será somente o tamanho estritamente necessário. isto implicaria que teríamos que alocar uma tabela MxN para conter todos os caracteres e isto nos levaria a disperdiçar algumas posições da memória que não chegaram nunca a conter algum caracter. k<COL. j++) for(k=0. int c = 10. obteremos a ordem desejada das strings sem ter que se preocupar em reescrever as strings em outra posição de memória. printf("\n"). isto é. Marcelo Ricardo Stemmer 107 . Podemos fazer isto. Isto fica claro na matriz acima. vamos acessar o quinto termo de linha. Queremos agora criar um vetor que contenha a terceira linha desta tabela. A diferença das notações é que a segunda utiliza a manipulação de ponteiros na sua declaração. queremos agora acessar o termo 4 desta linha. a) *(tabela + 2*5 + 4) Note que. Agora. • *(ptr + 2*5 + 4) == *(ptr + 14) : calculada a posição de memória onde está o referido termo. isto é. b) *( *(tabela + 2) + 4) Considere a declaração da seguinte tabela 4x5: int tabela[4][5]. basta utilizar o operador (*) para acessá-lo. /* eq. no caso 1000. Então. basta adicionar 4 ao ponteiro da linha. podemos tratar uma matriz mxn como sendo um vetor simples de inteiros. Abaixo. int linha[5] = *(tabela + 2). mostramos o armazenamento desta tabela na memória (Os endereços estão em números decimais para facilitar o entendimento). • ((ptr + 2*5) + 4) == (ptr + 14) : contém a posição de memória onde está o termo tabela[2][4]. • (ptr + 2*5) == (ptr + 10) : contém a posição incial da terceira linha da tabela (tabela[2]). cada elemento ocupará dois bytes e cada coluna com 5 elementos ocupará 10 bytes. se calcularmos a posição de memória ocupada por tabela[2][4]. no caso 1020 pois cada elemento ocupa 2 bytes (int). Mas como fazer para acessar um termo posicionado em tabela[i][j]? Como tabela é uma matriz para inteiros. Tabela: Mem\offset 1000 1010 1020 1030 i\j i\offset 0 1 2 3 0 0 13 20 31 40 1 2 15 22 33 42 2 4 17 24 35 44 3 6 19 26 37 46 4 8 21 28 39 48 Vamos tentar agora acessar o elemento tabela[2][4].Informática Industrial I DAS/UFSC Neste exemplo. Sabendo-se que a terceira linha começa após 2 linhas com 5 elementos. basta adicionar o número de termos contidos nestas linhas ao ponteiro da matriz e obtemos um ponteiro para o íncio da linha 2. Podemos fazer isto pelo método convecional de matrizes ou por ponteiros. Os dois métodos abaixo são equivalentes: int num = linha[4]. fazemos a atribuição de um elemento da matriz tabela. um vetor com 5 inteiros. 1 */ Note que. int num = *(linha + 4). que obtemos um ponteiro para o referido termo. estamos utilizando o ponteiro tabela para acessar os termos da matriz bidimensional. linha[4]. para uma matriz que contém 5 inteiros. pois as linhas são posicionadas na memória uma após a outra. onde a tabela tem dimensão 4x5. poderemos acessar o seu valor através de um ponteiro: • int * ptr = tabela : contém o endereço inicial da matriz. uma matriz é na verdade um vetor contendo outras matrizes de ordem menor. no caso 1028. Então. usando uma das duas declarações equivalentes: int linha[5] = tabela[2]. Com o ponteiro da linha. Na declaração acima. *(tabela+2) retorna o endereço da terceira linha da matriz tabela. e argv é uma matriz de string que contém todos os argumentos passados. o retorno do valor 0 indicará que o programa foi executado adequadamente. o endereço do quinto elemento é (*(tabela+2)+4) e o conteúdo deste endereço é *(*(tabela+2)+4).7 Argumentos da Linha de Comando C permite que um programa receba uma listas de parâmetros através da função main(). Este princípio é aplicado para matrizes de qualquer dimensão. Marcelo Ricardo Stemmer 108 . char* argv[]). Primeiro atribuímos a terceira linha da tabela a um vetor simples e depois acessamos o quinto elemento deste vetor. C nos permite criar ponteiros para ponteiros e fazer estruturas tão complexas e flexíveis quanto desejarmos. conseguimos acessar indiretamente o termo tabela[2][4]. Conhecendo como funciona os parâmetros da função main(). */ Assim. A forma geral da função main é dada por: int main(int argc.14159”. calculamos o endereço do quinto elemento nesta linha. indicando que o usuário forneceu 4 parâmetros ao programa.Informática Industrial I DAS/UFSC Desta forma.No caso.txt 2 3. “3. basta fazer: int tabela[4][5]. mas tenha cuidado para construir um código claro de forma a evitar problemas devido a um gerenciamento ruim destes ponteiros. “xadrex. C nos permite realizar o mesmo método de acesso. onde argc é o número de argumentos passados para a função.11. verificaremos que argc será igual a 4. você já pode utilizar a atribuição abaixo para obter os valores fornecidos. em outras palavras: tabela[j][k] = *(*(tabela + j) + k). equivalente a escrevermos &tabela[2][0]. Suponha que você tenha criado um programa chamado jogo e tenha executado ele no sistema operacional com a linha de comando: C:> jogo xadrex. A função main() nesta forma geral necessita retornar um valor indicado o resultado do programa ao sistema operacional.txt”. Sendo que os parâmetros estão armazenados em argv na forma de string e conterão os seguintes valores: argv[0] argv[1] argv[2] argv[3] == == == == “jogo”. Esta expressão é m ponteiro para ponteiro. Desta maneira. Entretanto. Portanto. Ao adicionarmos 4 a este endereço. Esta técnica pode fornecer grande velocidade de execução e economia de memória. “2”. 4.14159 Ao executar o programa passo-à-passo. que é 39. int num = *(*(tabela + 2) + 4). cubo[i][j][k] = *(*(*(cubo + i) + j) + k). O operador *(ptr) pode então ser aninhado para obter o valor final apontado pela seqüência de ponteiros. bastando converter o parâmetro do formato ASCII para o tipo de dado requerido : char * param = argv[3]. /* tabela[2][4]. sem criar este passo intermediário. Por isso. /* ponteiro para estrutura */ printf("Endereco #1: %p #2: %p\n". /* Aponta para a proxima estrutura */ printf("ptrl->titulo: %s \tptrl->autor: %s\n". ptrl.Informática Industrial I DAS/UFSC 4.preco = 89. assim ponteiros para estruturas são mais fáceis de manipular que matrizes de estruturas. O ponteiro ptrl pode então apontar para qualquer estrutura do tipo lista. Por exemplo. ptrl->titulo.95. struct lista *ptrl = 0. &livro[1]). 63. 321. Mas como proceder com ponteiros? Podemos fazê-lo de duas formas. A atribuição de um endereço a um ponteiro de estrutura funciona da mesma forma como uma variável qualquer.2f \t (*ptrl). ptrl->autor). char autor[30]. 102.2f\n".8 Ponteiros para Estruturas Como já mostramos ponteiros são mais fáceis de manipular que matrizes em diversas situações. "Machado de Assis". Marcelo Ricardo Stemmer 109 . &livro[0].50 }. ptrl->preco. adicionando-se o operador (*) na frente do nome da variável. /* mostra ponteiro para estrutura */ #include <stdio. double preco.preco). (*ptrl). ptrl = &livro[0]. printf("Ponteiro #1: %p #2: %p\n". ptrl++. { "Iracema". Vimos no capítulo sobre estruturas como fazer o acesso a um elemento de uma estrutura através do operador (. "Jose de Alencar". se quizermos ler o valor do preco da primeira estrutura da matriz livro.11. }. ptrl + 1).h> struct lista /* declara estrutura */ { char titulo[30]. int regnum. 70.25 } }.preco: R$%. printf("ptrl->preco: R$%. procederíamos da forma: livro[0]. a declaração de um ponteiro para uma estrutura é feita na forma : struct lista *ptrl. return 0. char * argv[]) { static struct lista livro[2] = { { "Helena".). empregando-se o operador (&): ptrl = &(livro[0]). O nosso próximo exemplo mostra como definir um ponteiro para estrutura e usá-lo para acessar os membros da estrutura. } A declaração é feita como se estivéssemos declarando uma variável de qualquer tipo. Várias representações de dados que parecem fantásticas são constituídas de estruturas contendo ponteiros para outras estruturas. int main(int argc. temos: ptrl->preco = 89.9 Alocação Dinâmica de Memória A linguagem C oferece um conjunto de funções que permitem a alocação ou liberação dinânmica de memória. Isto resolve o problema de termos um espaço de memória alocado para podermos armazenar os dados do programa. Este espaço de memória ficará alocado ao seu programa durante toda a execução deste. o programa liberará este bloco de Marcelo Ricardo Stemmer 110 .) para acessar um elemento desta estrutura. um ponteiro para estrutura seguido pelo operador (->) trabalha da mesma maneira que o nome de uma estrutura seguido pelo operador (. em tempo de execução. Entretanto. No caso do nosso exemplo. Aplicando no exemplo acima. podemos fazer com que sempre que a função for chamada. O operador (. podemos utilizar o operador (*) para obter a estrutura apontada por um ponteiro e depois empregar o operador normal (. o operador (->) conecta um ponteiro a um membro da estrutura.preco = 89. que pode conter mais variáveis globais. para que outros programas possam vir a utilizá-lo. fazer com que um programa aloque um determinado espaço de memória. como visto no capítulo de matrizes. Este segmento também é usado para passagem de parâmetros.) conecta a estrutura a um membro dela. • o segmento de pilha (“stack”). ela alocará um espaço de memória para armazenar a referida matriz e após o seu uso. Com a alocação dinâmica de memória. apesar do programa só utilizar uma vez esta matriz e.11. onde estão as instruções de máquina do programa em si. • o segmento de código. O heap é usado para a criação de variáveis dinâmicas. Toda a área de memória restante entre o fim do programa e o fim da RAM livre é chamado de heap. É importante notar que ptrl é um ponteiro.). ptrl>preco é uma variável double. você deverá declarar esta matriz na função.95. onde são alocadas as variáveis globais (extern). Para tal. mas ptrl->preco é um membro da estrutura apontada. utilize este espaço por um determinado tempo e depois o libere. durante a execução do programa). teremos: (*ptrl). Neste caso. o programa ao ser executado alocará somente um bloco fixo de memória para armazenar todos os seus dados. não precisar mas desta matriz e nem do espaço de memória alocado a esta. imagine que você precise de uma matriz temporária para armazenar alguns dados temporários durante a execução de uma dada função de manipulação de matrizes. que são criadas em run-time (isto é. onde as funções alocam provisóriamente suas variáveis locais (auto). • o segmento extra. O segundo método utiliza o operador (->) que nos permite acessar um elemento de uma estrutura apontada por um dado ponteiro. este método não otimiza a utilização do espaço de memória alocado. Aplicando-se este operador no problema acima. Desta forma. Por exemplo. podemos. Este tipo de variáveis é útil quando não se sabe de antemão quantas variáveis de um determinado tipo serão necessárias para a aplicação em questão.95.Informática Industrial I DAS/UFSC Primeiro. podemos alocar memória para um programa de acordo com a sua necessidade instântanea de memória. o que implicará que o computador irá alocar um bloco de memória para esta matriz. Quando escrevemos um programa utilizando o método de declaração de variáveis visto anteriormente (alocação estática de memória). A memória de trabalho do computador (RAM) usualmente é subdividida em vários segmentos lógicos dentro de um programa. Estes segmentos são: • segmento de dados. definidas em prerun-time. posteriormente. 4. Em outras palavras. 9. j<4. Este bloco de memória é solicitado ao sistema operacional que procura um espaço livre de memória para o programa. Este ponteiro void pode ser convertido para um ponteiro do tipo de dado desejado (int. }. O conceito de ponteiro para void deve ser introduzido para tratar com situações em que seja necessário que uma função retorne um ponteiro genérico. que possa ser convertido em um ponteiro para qualquer outro tipo de dado.2. malloc() retorna um ponteiro para uma área de memória suficiente para guardar um nova estrutura.1 Malloc() A função malloc() é utilizada para fazer a alocação dinâmica de um bloco de memória a um dado programa.Informática Industrial I DAS/UFSC memória para que outro programa o utilize. A função malloc() toma um inteiro sem sinal como argumento.h> struct xx { int numl. float. struct. void main() { struct xx *ptr = 0. } } Marcelo Ricardo Stemmer 111 .. Desta forma. A função retorna um ponteiro para o primeiro byte do novo bloco de memória que foi alocado. O exemplo abaixo mostra como a função malloc() opera. ptr). Desta forma. No próximo exemplo.) empregando-se o método de conversão de tipos apresentado na secção sobre tipos de dados (ver 4. Quando a função malloc() não encontrar espaço suficiente de memória para ser alocado.5). o programa irá liberar esta memória posteriormente. char chl. podemos utilizar a alocação dinâmica de memória para somente alocar a quantidade necessária de memória e no momento em que esta memória for requerida. printf("sizeof(struct xx) = %d\n". se executarmos esta função apenas uma vez. A cada chamada. . printf("ptr = %x\n".. 4. i. um ponteiro inválido. esta retornará um ponteiro NULL. Desta forma.. j++) { ptr = (struct xx *) malloc(sizeof(struct xx)).. o programa libera novamente esta memória ao sistema operacional. for(j=0.e. Se o sistema operacional achar um bloco de memória livre do tamanho do bloco solicitado. Outro exemplo de aplicação da alocação dinâmica de memória é na utilização de matrizes quando não sabemos de antemão quantos elementos serão necessários. No final do seu uso.11. Este número representa a quantidade em bytes de memória requerida. int j. i. mostraremos o seu emprego novamente. /* testa malloc() */ #include <stdio. este passa o bloco de memória para o controle do programa e não irá permitir que nenhum outro programa utilize esta memória enquanto ela estiver alocada. É importante verificar que o ponteiro retornado por malloc() é para um tipo void. permitindo assim que outros programas façam um uso mais adequado desta. sizeof(struct xx)).e. a alocação dinâmica de memória é utilizada em programas para alocar e liberar blocos temporários de memórias durante a execução de um programa (por isso é chamado alocação dinâmica). Este programa declara uma estrutura chamada xx e chama malloc() 4 vezes. em bytes.11.3 Free() A função free()libera a memória alocada por malloc() e calloc(). esta memória ficará insdiponível para o uso pelo sistema operacional para outros aplicativos. ou através do uso de um novo operador em C unário chamado sizeof(). De fato. A utilização consciente da alocação e liberação dinâmica de memória. a expressão sizeof(float) retornará o valor 4. pois malloc() retorna um ponteiro para ela. o programa não conhece o nome desta variável. exatamente como se tivessem sido declaradas no início do programa. 400 bytes. Se não for liberada.9. Por exemplo. Marcelo Ricardo Stemmer 112 . da variável ou do tipo de dado que está em seu operando. Feito isto. sizeof(long)). sizeof() forneceu o tamanho em bytes da estrutura para que malloc() pudesse alocar o espaço de memória requerido. memnova = (long *)calloc(100. como argumento. ou seja. que foi convertido para o tipo struct xx através da expressão: (struct xx *) 4. Há uma grande semelhança entre calloc() e malloc() que também retorna um ponteiro para void apontando para o primeiro byte do bloco solicitado. 4. Um uso típico é mostrado abaixo: long * memnova. Este operador produz um inteiro igual ao tamanho. então esta instrução alocará espaço para 100 unidades de quatro bytes. Aceita. permite em um uso otimizado da memória disponível no computador. pois a estrutura xx consiste em um caracter e um inteiro. Sempre que um espaço de memória for alocado.11. um ponteiro para uma área de memória previamente alocada e então libera esta área para uma possível utilização futura.Informática Industrial I DAS/UFSC Note que em nenhuma parte do programa declaramos qualquer variável estrutura. malloc() retornou um ponteiro do tipo void. este deve ser necessariamente liberado após o seu uso. A vantagem desta declaração é que ela permite que a chamada à função seja feita com um argumento ponteiro para qualquer tipo de dado. As variáveis criadas podem ser acessadas usando ponteiros. long usa quatro bytes. a variável estrutura é criada pela função malloc(). mas sabe onde ela está na memória. A cada chamada de malloc() devemos informá-la do tamanho da estrutura que queremos guardar. haja vista que um float ocupa 4 bytes. No programa exemplo. A função free()declara o seu argumento como um ponteiro para void. long * memnova.9. Nós podemos conhecer este tamanho adicionando os bytes usados por cada membro da estrutura.2 Calloc() Uma outra opção para a alocação de memória é o uso da função calloc(). usamos sizeof() em printf() e ele retorna 3. A função calloc() tem mais uma característica: ela inicializa todo o conteúdo do bloco com zero. memnova = (long *) calloc(100. No exemplo acima. A nova função aceita dois argumentos do tipo unsigned int. O primeiro argumento é o número de células de memórias desejada e o segundo argumento é o tamanho de cada célula em bytes. Então. sizeof(long)). os dados são traduzidos para caracteres e estes caracteres são escritos nos arquivos. Em um capítulo posterior. Utilize a idéia da lista ligada e da alocação dinâmica de memória.12 Manipulação de Arquivos em C Neste capítulo. Os membros devem armazenar o nome. a corrente é acessada através de um ponteiro para a primeira estrutura. Normalmente uma lista encadeada é criada dinamicamente na memória.1 Escreva um programa que receba duas strigns como argumentos e troque o conteúdo de string1 como string2.1 utilizando alocação dinâmica de memória. Isto é.10 Exercícios 11. chamado cabeça.5 A lista encadeada se assemelha a uma corrente em que as estruturas estão penduradas sequencialmente. A professora deve poder também lista os dados de todos alunos na forma de uma tabela na tela do computador.Informática Industrial I DAS/UFSC /* usa memnova */ free(memnova). A professora deve ser capaz de inserir e retirar alunos.3 Reescreva o programa do exercício 9. e poder editar os dados dos alunos. Escreva um programa que peça o tipo de comida e imprima os restaurantes que oferecem ete tipo de comida. e cada estrutura contém um ponteiro para a sua sucessora. Crie um programa com uma lista encadeada para armazenar dados de livros em uma biblioteca. o endereço. 11. 11. será apresentada novamente a manipulação de arquivos utilizando C++. e o ponteiro da última estrutura tem valor NULL (0) indicando o fim da lista. /* libera a memória alocada */ 4. se a string recebida é “Saudacoes” deve ser modificada para “seocaduaS”.11. 11. o preço médio e o tipo de comida.8 Escreva um programa para montar uma matriz de estruturas para armazenar as notas de 40 alunos. Arquivos em modo texto. 11. depois seguem as notas em lista e na última coluna deve ser calculada a média até o presente momento. 11.4 Reescreva o programa do exercício 9.1 Tipos de Arquivos Uma maneira de classificar operações de acesso a arquivos é conforme a forma como eles são abertos: em modo texto ou em modo binário. fica mais fácil de compreender os seus formatos e localizar possíveis erros.3 utilizando alocação dinâmica de memória.2 Escreva um programa que inverta a ordem dos caracteres de uma string. Marcelo Ricardo Stemmer 113 . 4. veremos brevemente a manipulação de arquivos em C. A lista de alunos deve ser indexada pelo nome destes. operam em dados armazenados em formato texto. 11. ou seja. 11. Por esta razão.12. O menor preço deve ser o primeiro da lista.7 Crie uma estrutura para descrever restaurantes. 4. Por exemplo. a terceira a data de nascimento. Crie uma lista ligada que apresente os restaurantes de um certo tipo de comida indexados pelo preço.6 Crie um programa com lista encadeada para catalogar clientes e fitas em uma vídeo locadora. O primeira coluna da matriz deve conter o nome do aluno. a segunda o telefone. Append. assim eles podem se comunicar. escrita) requer um apontador para uma estrutura do tipo FILE: FILE *File_ptr. Este tipo é definido na biblioteca “stdio. Se o arquivo estiver presente ele será destruído e w reinicializado. abre arquivo para leitura. para operar com arquivos. Append.) e por isso esta retornará um ponteiro inválido. abertura e fechamento C declara um tipo especial de estrutura. operam em dados binários. ou um novo arquivo será criado. abre arquivo para escrita. enquanto que na forma binária são guardados com estão na memória. ela preenche a estrutura FILE com as informações necessárias para o programa e para o sistema operacional. Se não existir. Primeiro. Uma outra diferença entre o modo texto e o modo binário é a forma usada para guardar números no disco. onde as opções para a abertura do arquivo estão listadas abaixo: I/O mode Função: Read. precisamos fechá-lo. r Write. ele será criado. os dados escritos neste formato são escritos na forma binária. arquivo contém texto dados em ASCII. fechamento. etc. que deve ser incluida na compilação com a diretiva #include para permitir operações sobre arquivos. ou seja. abre arquivo para escrita. a localização de seus buffers de dados. b A função fopen() executa duas tarefas.”<I/O mode>). Read. Os dados serão adicionados ao fim do arquivo se a este existir. Marcelo Ricardo Stemmer 114 . O arquivo deve existir. arquivo inexistente. leitura. caso contrário o seu programa pode vir a ter uma falha séria. Se não existir. a+ Text. A função fopen() pode não conseguir abrir um arquivo por algum motivo (falta de espaço em disco. 4. arquivo contém dados em binário. dois bytes para um inteiro.h”.2 Declaração.12. chamada FILE. A abertura de um arquivo é feita com a função fopen(): File_ptr = fopen(“Nome do Arquivo”. Se o arquivo estiver presente ele será w+ destruído e reinicializado. O fechamento de um arquivo é feito com a função fclose(): fclose(File_ptr). abre um arquivo para leitura e gravação. isto é. Na forma de texto. ele será criado. t Binary. etc. fopen() retorna um ponteiro do tipo FILE que aponta para a localização na memória da estrutura FILE. Por isso. se o arquivo está sendo lido ou gravado. tais como: seu atual tamanho. abre um arquivo para atualizações ou para adicionar dados ao seu final. contendo o valor NULL (0). não necessitando de nenhuma conversão do tipo do dado utilizado para ASCII e ocupando bem menos memória de disco (arquivos menores). os números são guardados como cadeias de caracteres.Informática Industrial I DAS/UFSC Arquivos em modo binário. teste sempre se o ponteiro fornecido por fopen() é válido antes de utilizado. Toda operação realizada sobre um arquivo (abertura. Segundo. Write. quatro bytes para float e assim por diante. Os membros da estrutura FILE contêm informações sobre o arquivo a ser usado. abre um arquivo para leitura e gravação. Quando terminamos a gravação do arquivo. O arquivo deve existir e pode ser r+ atualizado. Perceba que no exemplo anterior de leitura de caracteres.”w”). A marca de fim de arquivo pode ser diferente para diferentes sistemas operacionais. não esqueça de fechar um arquivo. Abaixo. O seu arquivo stdio. Primeiro. 4. apresentamos exemplos destas funções: Escrita #include <stdio. A função exit() difere da função fclose() em vários pontos. Segundo. o sistema operacional estava salvando as alterações em um buffer antes de escrever estes dados no arquivo. Marcelo Ricardo Stemmer 115 .4 Fim de Arquivo (EOF) EOF é um sinal enviado pelo sistema operacional para indicar o fim de um arquivo. O sinal EOF (Fim de Arquivo) enviado pelo sistema operacional para o programa C não é um caracter. Assim. em seus programas. O fim de um arquivo pode também ser determinado utilizando-se a função feof(). o caractere de código ASCII 255 decimal (0xFF em Hexa) será interpretado como EOF.3 Leitura e escrita de caracteres A função usada para ler um único caracter de um arquivo é getc() enquanto que a função putc() escreve um caracter em um arquivo. o valor de EOF pode ser qualquer.h> FILE *fileptr. Por isso. quando não conhecemos de antemão a quantidade de caracteres deste arquivo. use EOF para testar fim de arquivo.h define EOF com o valor correto para o seu sistema operacional. Neste exemplo. EOF é usado para ler todos os caracteres de um dado arquivo. e sim um inteiro de valor –1 e está definido em stdio. senão os seus dados podem ser perdidos e o arquivo não seja criado adequadamente. mychar). fclose(fileptr). no caso de ser um arquivo novo.12.h. fileptr = fopen(filename. exit() fecha todos os arquivos abertos.fileptr). Estas áreas incluem a estrutura FILE e o buffer. Este procedimento é executado para otimizar o tempo de acesso ao disco empregado pelo sistma operacional. char filename[65]. Uma outra razão para fechar o arquivo é a deliberar as áreas de comunicação usadas.Informática Industrial I DAS/UFSC Quando fechamos um arquivo é que o sistema operacional irá salvar as suas modificações ou até mesmo criar o arquivo.12. assim.”r”). A função fclose() simplesmente fecha o arquivo associado ao ponteiro FILE usado como argumento. int mychar. char mychar.h> FILE *fileptr. Uma outra função que fecha arquivos é a função exit(). Leitura #include <stdio. } fclose(fileptr). nós usamos uma variável inteira para guardar os caracteres lidos para que possamos interpretar o sinal de EOF. while(mychar != EOF) { printf(“%c”. fileptr = fopen(filename. putchar(mychar. Se usarmos uma variável do tipo char. mychar = getchar(fileptr). Até então. int i = 0. char filename[65]. a função exit() também termina o programa e devolve o controle ao sistema operacional. 4. mychar = getchar(fileptr). que recebe como parâmetro um ponteiro válido para a estrutura FILE. para que estejam disponíveis a outros arquivos. Queremos usar todos os caracteres de 0 a 255 em nosso arquivo e uma variável inteira nos assegura isto. /* fprintf(fileptr. 80. pois gets() acrescenta o caractere NULL (‘\0’) na próxima posição livre. line). O terceiro argumento é um ponteiro para a estrutura FILE do arquivo a ser lido. No programa exemplo abaixo. toma dois argumentos.h. este número deve ser pelo menos um maior que o número de caracteres lidos. sendo o primeiro a matriz de caracteres que será gravada e o segundo o ponteiro para a estrutura FILE do arquivo a ser gravado. char line[81]. _streams[] foi criada como uma matriz de estruturas FILE. A função gets() lê uma linha por vez de um arquivo texto. /* pode ser usado aqui no lugar */ fclose(fileptr). /* fscanf(fileptr. fgets(line. A função termina a leitura após ler um caractere de nova linha (‘\n’) ou um caractere de fim de arquivo (EOF). Escrita: #include <stdio. A função gets() toma 3 argumentos. char filename[65]. encontrará várias constantes simbólicas definidas como: #define #define #define #define #define stdin stdout stderr stdaux stdprn (&_streams[0]) (&_streams[1]) (&_streams[2]) (&_streams[3]) (&_streams[4]) Estas constantes podem ser usadas para acessar qualquer um dos 5 arquivos padrão que são predefinidos pelo MS-DOS e abertos automaticamente quando o seu programa inicia a sua execução e fechados ao seu fim. Na verdade.Informática Industrial I DAS/UFSC 4. fazemos isto explicitamente com o caracter ‘\n’.12.”%s\n”. ”w”). fileptr = fopen(filename. /* pode ser usado no lugar de fgets */ 4. fileptr). line) */ fputs(“\n”. Observe que a função fputs() não coloca automaticamente o caractere de nova-linha no fim de cada linha. Marcelo Ricardo Stemmer 116 .h> FILE *fileptr. O segundo é um número inteiro que indica o limite máximo de caracteres a serem lidos. */ close(fileptr). “%s”. Se você perder um tempo e analisar o seu arquivo stdio.h> FILE *fileptr.12. fileptr). char filename[65]. ”r”). Desta forma. char line[81].5 Leitura e escrita de strings A função fputs() escreve uma string em um arquivo e. /* dos dois fputs */ Leitura: #include <stdio. fileptr). O primeiro é um ponteiro para o buffer onde será colocada a linha lida. fputs(line. fileptr = fopen(filename. por isso.6 Arquivos Padrão C define um conjunto de arquivos padrão utilizados para acessar alguns periféricos do computador (como a impressora) ou para ler da entrada padrão (normalmente o teclado) ou escrever para a saída padrão (normalmente a tela). “rw”). que como scanf(). como apresentado anteriormente. out. fprintf(fptr. &size). fscanf(fptr. Como exemplo.h> FILE *fptr. 80. A instrução: fputs(string. A diferença consiste que fscanf() lê um dado de um arquivo e recebe um ponteiro para FILE como primeiro argumento. basta adicionar o caracter ‘b’ no I/O Mode da função open(). 4. int size = 0. fptr = fopen(“dados. todas as possibilidades de formato de printf() operam com fprintf(). Estas funções são empregadas para escrever/ler os dados armazenados em um bloco de memória (um buffer de memória) em um arquivo. Exemplo : #include <stdio. Esta função é similar a printf() exceto que o ponteiro para FILE é tomado como primeiro argumento. “%d”. “%s %d %f”. Normalmente. Você pode usar os ponteiros FILE definidos em stdio.7 Gravando um Arquivo de Maneira Formatada Nos capítulos iniciais apresentamos a função printf() para imprimir na tela dados de forma formatada. stdin).Informática Industrial I DAS/UFSC Nome: stdin stdout stderr stdaux stdprn Periférico: Standard input device (teclado) Standard output device (tela) Standard error device (tela) Standard auxiliary device (porta serial) Standard printing device (impressora paralela) Cada uma destas constantes pode ser tratada como um ponteiro para uma estrutura FILE dos arquivos in. O primeiro é um ponteiro do tipo void que aponta para a localização na memória do dado a ser gravado.h para acessar os periféricos predefinidos pelo MS-DOS ou usar seus nomes e definir os ponteiros necessários. 13. Para realizar a mesma tarefa. aux e prn respectivamente. As funções apresentadas anteriormente podem ser usadas para ler e escrever no modo binário.45). Aplicações típicas e na escrita/leitura de dados complexos como matrizes e estruturas. entretanto apresentaremos aqui duas novas funções que facilitam este processo: fwrite() e fread(). fclose(fptr). O segundo argumento é um número inteiro que indica o tamanho do tipo de dado a ser gravado. Como em printf().12. “Casa Nova”. podemos formatra os dados de várias maneiras.12. entretanto não para escrever na tela mas sim para um arquivo.txt”.8 Leitura e escrita de valores binários Quando desejamos operar com arquivos no modo binário. A função fwrite() toma 4 argumentos. foi criada a função fprintf(). pode-se utilizar o operador Marcelo Ricardo Stemmer 117 . 4. err. stdprn). a instrução: fgets(string. 12. lê um dado formatado. lê uma string do teclado. imprimirá uma string na impressora. Da mesma forma foi criada a função fscanf(). “rb”). os dados são enviados a impressora. O arquivo de entrada deve ser fornecido na linha de comando. reescrevendo a lista no arquivo. Escrita: fileptr = fopen(filename. incluindo matrizes e estruturas. As funções fread()e fwrite() trabalham com qualquer tipo de dado. O terceiro argumento é um número inteiro que informa a fwrite() quantos itens do mesmo tipo serão gravados. Permita que o usuário possa retirar um livro desta lista. “wb”). sizeof(dados). refaça o problema 11. podendo ser zero caso nenhum dado tenha sido lido. Quando o programa é executado para um arquivo já criptografado.5 Como o exemplo anterior. fread(&dados. Leitura: fileptr = fopen(filename. o número será menor que o valor do terceiro argumento. Normalmente este número deve ser igual ao terceiro argumento. apagando-o do arquivo.2 Escreva um programa que imprima o tamanho de um arquivo em bytes.fileptr). 12.9 Exercícios 12.Informática Industrial I DAS/UFSC sizeof() para se obter este valor.fileptr).fileptr).3 Escreva um programa que criptografa um arquivo usando o operador de complemento de bit-a-bit (~). O segundo indica também a quantidade de bytes do tipo de dado a ser lido. o programa aguarda o pressionamento de uma tecla. Se for encontrado o fim do arquivo.1. sizeof(dados). O terceiro argumento informa a quantidade de itens a serem lidos a cada chamada. Utilize o modo texto para a manipulação de arquivos. } fclose(fileptr).1 . A cada impressão de 20 linhas. 12. Se "filename" for inicializado com “prn”. e o quarto argumento é um ponteiro para a estrutura FILE do arquivo a ser lido. agora salvando a lista de livros em um arquivo. ou adicionar um livro em uma posição determinada na lista.1 . A função fread() retorna o número de itens lidos.4 Refaça o problema 11. Marcelo Ricardo Stemmer 118 . O primeiro é um ponteiro void para a localização da memória onde serão armazenados os dados lidos.6 mas agora utilizando o modo binário. 12.sizeof(dados).12. 12. Exemplo: fileptr=fopen(filename. fwrite(&dados.”rb”). O quarto argumento é um ponteiro para a estrutura FILE do arquivo onde queremos gravar. A função fread() toma também 4 argumentos. O nome do arquivo deve ser fornecido na linha de comando.5. 4. e armazenam números em formato binário. while(!feof(fileptr)) { fread(&dados. o arquivo é recomposto e volta ao original.1 Escreva um programa que imprima um arquivo na tela de 20 em 20 linhas. tapete. sua reusabilidade e facilidade de manutenção. Podemos até criar um objeto chamado “sala” que contém todos os objetos presente na sala descrita pelo arquiteto e permitir que este arquiteto venha criar futuramente outros objetos como “cozinha” ou “quarto” e possa. pois não conseguem entender o modelo da realidade gerado por este programa ou a sua estrutura. os objetos. o tom da sua cor. modelar toda uma residência. etc. daquilo que o arquiteto considera importante que esteja no modelo. assim. precisamos definir as relações entre estes. o seu custo. não possui todas as facilidades e mecanismos de uma linguagem puramente Orientada a Objetos como Smalltalk. parede. Por exemplo. Por isso. Modelar um determinado ambiente complexo utilizando-se somente as estruturas e funcionalidades disponíveis por C (linguagem estrutural) é uma tarefa árdua. C++ é uma espécie de adaptação de C a metodologia de Orientação a Objetos e. enquanto que para um arquiteto significa definir a textura da mesa. Apesar do seu ótimo desempenho em termos de programas otimizados. é importante ter em mente. podemos facilmente listar alguns objetos que podem ser definidos: janela. Algumas linguagens como Smalltalk refletem muito mais a “cultura” ou a “metodologia” Orientada a Objetos. devem ser descritos. Entretanto. estamos na verdade criando um modelo da realidade e usando este modelo para analisar e estudar esta realidade. Por exemplo. são propriedades de um terceiro objeto chamado “parede”. quadro. suponha que você esteja criando um programa para permitir que um arquiteto crie um modelo gráfico de uma sala-de-estar e apresente este modelo ao seu cliente. mesa. porta. primeiramente o arquiteto terá que identificar os objetos que compõem a sala-de-estar que. favorecendo a geração de programas segundo esta metodologia. por isso. como outro objeto “parede” pode não conter uma “janela” mas um objeto do tipo “quadro”. A Orientação a Objetos busca modelar um ambiente utilizando-se dos próprios elementos presentes neste ambiente.Informática Industrial I DAS/UFSC 4. A linguagem C++ foi criada a partir da linguagem C. Com este breve esclarecimento já apontamos algumas das propriedades vantagosas fornecidas pela programação Orientada a Objetos. velozes e portáteis. ou seja. Após a definição dos objetos que compõem um dado ambiente. etc. vaso de flores. ou seja. Todo ambiente pode ser modelado e simulado a partir de uma descrição dos objetos que o compõe e das relações entre eles. Neste caso. Um programa de computador sempre busca representar uma dada realidade (mundo real ou modelo abstrato: matemático) através de uma linguagem de programação. ou seja. Empregando a metodologia de Orientação a Objetos.13 Programação em C++ A linguagem C foi e continua sendo uma das linguagens mais importantes na área da informática. representar o objeto “mesa” pode significar para um marceneiro definir a sua geometria. o tipo de material. C++ herda de C a capacidade de gerar Marcelo Ricardo Stemmer 119 . sofá. a durabilidade desta. considerando o nível de abstração do seu modelo. criou-se uma forma totalmente nova e revolucionária para se modelar e simular um ambiente dado (mundo real ou sistema abstrato): a Orientação a Objetos. acrescentando novas estruturas e mecanismos que possibilitam a geração de programas segundo a metodologia de Orientação a Objetos. as necessidades do seu cliente antes de criar um modelo super detalhado e ineficiente. Quando criamos qualquer programa simples de computador. Neste sentido. A quantidade de objetos e o nível de detalhe da sua descrição dependerão necessariamente do nível de abstração do modelo. Por esta razão. precisamos definir que um objeto “porta” e um objeto “janela” estão posicionados sob a mesma parede. Assim. Por exemplo. sofreu duras críticas com relação a qualidade do código gerado considerando-se outros aspectos de relevância da engenharia de software como: legibilidade do código. o tipo de verniz requerido e o tipo do seu acabamento. O nível de detalhe com que criamos um programa depende diretamente do nível de detalhe necessário para modelar o ambiente de acordo com as necessidades impostas pelo usuário. alguns programadores em C não conseguem muitas vezes entender determinados códigos em C. o que permite um mais fácil controle e expansão dos mesmos. podem ser empregados para representar um outro ambiente. buscaremos agora apresentar os mecanismos mais importantes fornecidos pela linguagem C++. Poderemos. suponha que na hora em que o programa estiver desenhando o objeto ”mesa” na tela para o cliente do arquiteto apareça algum defeinto na mesa. basta alterar as características de um objeto "mãe" para que todos os objetos "filhos" (que herdaram propriedades) sejam também automaticamente alterados de forma correspondente. otimizados. para representar o ambiente sala-de-estar. A otimização de programas freqüêntemente requer uma violação das próprias regras de programação orientada a objeto. Posteriormente. • • Estas desvantagems tem se tornado menos críticas nos últimos anos devido ao grande aumento da velocidade de processamento dos computadores bem como ao aumento de sua capacidade de memória. • difícil otimização de tempo de execução dos programas. fazem com que C++ seja mais atrativo para a geração de médios e grandes sistemas. isolar e. utilizar o mesmo objeto “mesa” para representar o ambiente cozinha. Por exemplo. Isto permite que outro programador possa entender o programa criado. ainda.Informática Industrial I DAS/UFSC programas pequenos. Neste aspecto. grande complexidade de gerenciamento interno das estruturas dos objetos. Como vantagems pode-se citar: • existem muitas ferramentas de apoio ao desenvolvimento de programas. descrevendo não somente a sintaxe de C++ mas também conceitos envolvidos na programação Orientada a Objetos. haviamos definido o objeto “mesa”. possamos localizar. facilmente localizar erros no código fonte. sem precisar redefini-lo novamente. • a programação orientada a objeto se baseia fortemente na própria forma de pensar humana. a posição deste objeto na sala). então. A modelagem orientada a objetos fornece uma estrutura bem clara para o código fonte do programa. ou o mecanismo responsável pelo desenho deste objeto na tela não está operando corretamente. Por exemplo. apresentaremos os demais mecanismos da orientação a objetos. Marcelo Ricardo Stemmer 120 . • os programas tem uma estrutura altamente modular. Por exemplo. em seguida. Estes motivos propiciaram a grande difusão que a linguagem C++ vem sofrendo nos últimos anos. Por outro lado. Isto nos permite que. facilmente concluir que: ou o objeto mesa esta mal representado (erro dentro da definição do objeto mesa). entretanto. Podemos. ao contrario da forma algorítmica e procedural da programação convencional. Entretanto os ganhos em reusabilidade e em diminuição dos tempos de manutenção do programa. apresentaremos como C++ brevemente quais são as novidades da linguagem C++. de “baixo-nível” e portáveis. rapidamente. corrigir este erro. há também desvantagems relativas a esta forma de programação: grande necessidade de memória. A programação orientada a objeto se baseia no encapsulamento de uma estrutura de dados com as próprias rotinas de tratamento dos mesmos e na capacidade de herança destes dados e rotinas por outros objetos derivados. Emprega-se C basicamente quando temos que fazer um programa em pouco tempo. ou a relação deste objeto com os demais esta mal definida (por exemplo. Nesta etapa do trabalho. Neste capítulo. A reusabilidade advém do fato que objetos definidos para representar um dado ambiente. ganhamos em tempo de desenvolvimento. A geração de códigos em C++ requer normalmente um tempo maior de desenvolvimento que um programa em C normal. com grandes restrições na dimensão do código e no tempo disponível para o processamento do programa (requisistos de tempo-real). o que implica em velocidade de execução menor. A programação orientada a objeto tráz consigo uma série de vantagems e também algumas desvantagems. reutilizar partes em outros programas e. int regnum. // variável local recebe o valor da var. // variável extern.13. Em C++. Assim. podemos redefinr a estrutura “list” da seguinte maneira : struct list { char titulo[30]. Marcelo Ricardo Stemmer 121 . } A linguaguem C++ apresenta uma outra forma de comentários: uma linha iniciada pelo para de caracteres de barra “//”. referenciada por: ‘n’ ou ‘::n’ void calc() { int n = 5.13. Veja o exemplo: int n = 10.Informática Industrial I DAS/UFSC 4. // declaração de uma variável do tipo ‘list’ Em C++. Em C++. primeiro declaramos as variáveis e depois podemos efetuar uma dada instrução. Mesmo que não tenhamos usado o typedef. Essa ampliação consiste em tornar visível ou inacessível membros particulares de estruturas e classes. A própria etiqueta especificando nome (estrutura ou união) já é um tipo nome. char autor[30]. }. tudo é comentário até o final da linha. o C++ ampliou o conceito de escopo para variáveis de tipos compostos (estruturas e classes).2 Sintaxe & Variáveis A linguagem C permite a declaração de variáveis dentro de uma função. list * livros. além destas formas pode-se declarar uma variável em qualquer ponto de um programa. você estará acessando dentro da função somente a variável local. double preco. Abordaremos isto quando do estudo de classes. Ao utilizar o nome da variável. // variável auto. Além deste default. não é necessário utilizar a palavra typedef para se definir uma estrutura. você pode utilizar o operador :: (escopo) para acessar a variável global. inclusive entre instruções ou mesmo dentro delas. toda variável que não for declarada explicitamente como static. somente antes da chamada a instruções que desta função. como indicam os seguintes exemplos: // Este é um comentario em C++ // Após a barra dupla. Entretanto. local n = ::n. extern. Suponha que ao definir uma função você tenha criado uma variável local com o mesmo nome que uma variável global (extern).1 Palavras-chave em C++ catch class delete friend inline new operator private protected public template this virtual A linguagem C++ inclui apenas 14 novas palavras reservadas às já existentes no C: 4. o compilador C++ permitirá declarações de variáveis estruturadas sem a necessidade de struct. ou seja. será considerada do tipo extern automaticamente. 3. O objeto cout utiliza flags de formatação para sinalizar as opções de formatação dos dados. onde. Abaixo apresentamos alguns exemplos da utilização de cout.1 A stream de saída cout Cout é um objeto de uma clase de I/O predefinida em C++. << : é o operador de inserção usado a fim de direcionar a saída de dados para a saída padrão (vídeo).. g = 3.h>. for(int i =0. Sintaxe de cout : cout << expressão. expressão : é qualquer combinação de caracteres ou variável.13.00 valor = 2. Resultado x = 2 1. = ” “\nsex = ” << ch.1. o ao terminal de vídeo. cout e cerr. Essa formatação é feita pela própria stream. mais adequadas ao paradigma da Orientação a Objetos. ” << g.Informática Industrial I DAS/UFSC 4. Variáveis int x = 2. mostramos o uso do caracter especial ‘\n’ para fazer com que o computador pule uma linha antes de continuar escrevendo dados na tela. float f = 1.3 Laços e Comandos de Decisão A linguagem C++ não modifica a sintaxe ou o comportamento dos laços e comandos condicionais do C. Porém. Note que em nenhuma das declarações da stream cout são formatados os dados a serem apresentados.4. Para mostrar os dados em um programa C++. destinados à entrada e saída de dados via terminal ou via arquivos. sendo esta biblioteca toda definida em termos de classes de objetos. Os flags (sinalizadores) de formato (definidos em <iomanip.e. mas define novas bibliotecas. Podemos utilizar todos os caracteres especiais definidos para printf() da mesma maneira que utilizamos agora ‘\n’.h>) são os seguintes: Manipulador skipws left Right Internal Dec Marcelo Ricardo Stemmer Significado ignora o espaço em branco na entrada saída ajustada à esquerda saída ajustada à direita preenchimento após indicador de sinal ou base conversão em decimal 122 . Exemplo: int j =0.14 sex = F No último exemplo acima. j=3. As definições e declarações necessárias para o uso de “streams” estão contidas no arquivo <iostream.4 I/O em C++: Stream A linguagem C++ segue permite a utilização dos mecanismos de I/O definidos em C. double dou = 2.14. Nela estão os três objetos: cin.13.20 3. permite a declaração de variáveis na região de inicialização do for. antes do laço estas variáveis inexistem. char ch = ‘F’. i = j++ ) 4.2. i.13. C++ cout << “x = ” cout << f << “ cout << “valor << dou << << x. Por default cout está associada a uma saída padrão (stdout). i+j<10. ou seja. Uma lista completa destes caracteres está em 4. deve-se utilizar a stream cout. 4. Essas bibliotecas constituem a chamada biblioteca Stream do C++. Alguns manipuladores são idênticos ao sinalizadores.12345E2 cout. limpa os bits de formato em ins ou outs especificadas. cout << 12. Os manipuladores de formato são utilizados para manipular a formatação dos dados em streams de saída. default n = 0. // para ligar cout. a diferença está na forma mais compacta e na inclusão de outra biblioteca de classes <iomanip. stderr depois de inserção A sintaxe para usar esses sinalizadores (ou flags) é a seguinte: cout. // para desligar cout. bor = 234.23E2 usa notação de ponto flutuante 1.345 // Imprimirá: 12. a definição de tamanho de campos é usada para alinhamento e estética de um relatório.unsetf(ios::scientific). int can = 42.unsetf(ios::<sinalizador>).h> void main() { float lap = 4. Marcelo Ricardo Stemmer 123 .345. Isto significa que podemos definir o número de colunas que serão ocupados por um valor ou texto a ser impresso. Manipulador dec oct hex ws endl ends flush setbase(n) resetiosflags(long) setiosflags(long) setfill(int n) setprecision(int n) setw(int n) Significado passa ara base decimal passa ara base octal passa ara base hexadecimal extrai caracteres de espaço em branco insere nova linha e libera stream insere término nulo em string ‘\0’ libera o buffer de saída ostream alocado ajusta o formato de conversão para a base n.h> #include <iomanip.setf(ios::<sinalizador>). ajusta o caracter de preenchimento para n ajusta a precisão do ponto flutuante para n ajusta o tamanho do campo para n Exemplo do uso destes manipuladores: // Exemplo do emprego de Cout #include <iostream.23 libera (flush) todas as streams depois da inserção libera (flush) stdout.5421234546. cad = -8. // Imprimirá : 0.h>. ajusta os bits de fomato em ins ou outs especificadas. Geralmente.875.Informática Industrial I DAS/UFSC oct Hex Showbase showpoint uppercase showpos scientific fixed unitbuf stdio conversão em octal conversão em hexadecimal mostra o indicador de base na saída mostra ponto decimal (para float) saída hexadecimal maiúscula mostra o sinal ‘+’ em inteiros positivos usa notação científica de ponto flutuante 1.345 O objeto cout permite estabelecer o tamanho de um campo para a impressão. cout << 12.setf(ios::scientific). dec e #include <iostream. Cin faz isto automaticamente. o teclado). scanf(“%f %f”. &ch). dec e oct apresentados anteriormente.4. 4. &g). " << setw(12) << "TYE". cin >> dou >> ch. o compilador sabe que este operador não será o operador para deslocamento de bits mas sim o operador de leitura de dados. i.e. Podemos ler números em outras bases numéricas. cin >> x. ignorando o tamanho do campo. Múltiplas entradas são digitadas separadas por um espaço em branco. &f. onde >> : é o operador de extração usado para direcionar a entrada de dados à entrada padrão (teclado).&x). cin >> f >> g. O operador >> pode apresentar-se diversas vezes numa instrução com a finalidade de permitir a introdução de diversos valores ao mesmo tempo. de acordo com a declaração da variável. bor. double dou. &dou. Na tabela a seguir. Outro exemplo do emprego destes manipuladores: // Exemplo do emprego de hex. scanf(“%Lf %c”.') << "Fitas << << << << lap. apresentamos alguns exemplos da leitura de dados através de cin. Através do contexto. A sintaxe de cin é: cin >> variável. int x. setprecision(2).g. "\n\t" << "Lapis " << setw(12) "\n\t" << "Borracha " << setw(12) "\n\t" << "Canetas " << setw(12) "\n\t" << "Cadernos " << setw(12) "\n\t" << setfill('. Note que em C++ não é necessário formatar o dado que está sendo lido.13. << dec << n. cad.2 A stream de entrada cin A forma de entrar com dados em um programa C++ é através do objeto cin. Tratra-se de um fluxo associado à entrada padrão do computador (stdin. utilizando os manipuladores hex. cout << "\n" << "Hexadecimal \t" cout << "\n" << "Decimal \t" cout << "\n" << "Octal \t" } oct << hex << n. Observação: Se o tamanho do campo especificado em setw for menor que o tamanho mínimo necessário para imprimir o valor associado. variável : é o nome da variável onde desejamos guardar os valores lidos. char ch. << oct << n. Variáveis C++ C scanf(“%d”. a impressão utilizará o numéro necessário de colunas. O objeto cin faz com que o programa aguarde que você digite o dado a ser adquirido e pressione a tecla [ENTER] para finalizar a entrada. float f. O objeto cin entende um espaço em branco como término de uma entrada e o [ENTER] como finalizador geral.Informática Industrial I DAS/UFSC cout cout cout cout cout cout cout } << << << << << << << "\n\n" << setiosflags(ios::left).h> void main() { int n = 15. can. Marcelo Ricardo Stemmer 124 . int cor). pois o compilador deve conhecer de antemão o código da função para poder inseri-la dentro do programa. double cubo(double n). Isto é necessário. cin >> hex >> n. 4. char ch. quando colocada como primeiro elemento do cabeçalho da definição de uma função.13.5. int n2 = pares(20). seu códigodeve ser escrito antes de main(). int = 0). caso a chamada da função omita algum parâmetro. todos os subsequentes deverão ser omitidos e assim por diante.Informática Industrial I DAS/UFSC int n = 0. Podemos escrever funções que tenham parâmetros inicializados com um valor default e parâmetros não-inicializados. // protótipo Se o primeiro argumento foi omitido.13. int cor = 0).13. se a função for chamada em main(). A palavra-chave inline. Por exemplo. um dos motivos para escrever funções é o de poupar memória. Exemplo: void linha( int n = 20. Todas as funções apresentadas na secção 4. Quando a função é chamada. int n1 = pares(20. A biblioteca stream define outras funções para leitura e escrita de dados que não serão aqui apresentadas.13. causa a inserção de uma nova cópia da função em todo lugar onde ela é chamada. é a lista de parâmetros passada para ela que permite ao sistema identificar qual é o código adequado.3). float cubo(float n).3 Funções Inline int cubo(int n). A forma de definir valores default é explicitá-los na declaração da função. Ou seja.2 Sobrecarga de Funções Sobrecarregar funções significa criar uma família de funções com o mesmo nome. mas após a primeira inicialização todos os parâmetros seguintes devem ser inicializados. Uma função é um código presente uma única vez no programa que pode ser executado muitas vezes. Se o segundo argumento for omitido. // Declaração válida. O exemplo a seguir apresenta a declaração do default de uma função e chamadas por ele viabilizadas: unsigned int pares(int. Assim. mas com a lista de parâmetros diferentes. lembrando que devemos definir cada função como se fosse única: int cubo(int n). a função pode usar o default previamente definido. char ch = ‘*’. Funções sobrecarregadas devem ter a lista de parâmetros diferentes ou em número ou em tipo. Quando uma Marcelo Ricardo Stemmer 125 . inline A definição de uma função inline deve preceder a primeira chamada a ela. 4. os valores default não devem ser repetidos na definição. podemos definir a família de funções abaixo.5.1 Funções Valores Default Para Argumentos de uma Função C++ permite a definição de valores default para argumentos de funções. todos os subsequentes deverão ser omitidos.3 podem ser aqui empregadas.5 4.5. 4. omitindo ou não o nome das variáveis. // Declaração inválida void linha(int n. pois o compilador reconhece nisto uma duplicidade de default. Uma vez definidos na declaração. Isto significa que. análogos as funções malloc() e free(). Por exemplo. Uma referência não é uma cópia da variável a quem se refere. enquanto que new descobre esse tamanho automaticamente. Este tipo de preocupação já não existe com passagem por referência. Os exemplos de argumentos de funções vistos até o momento são passados por valor ou por ponteiros. } float& p = 15). 4.13. o tamanho do tipo para o qual se pede memória deve ser informado à malloc().6 Alocação Dinâmica de Memória em C++ A alocação dinâmica de memória em C++ é feita com os operadores new (alocação) e delete (liberação). a função chamada cria novas variáveis do mesmo tipo dos argumentos e copia nelas o valor dos argumentos passados. As instruções: int n. Funções que recebem argumentos por referência utilizam o operador & somente na definição do tipo do argumento e possuem chamadas idênticas a uma função normal. É a mesma variável sob nomes diferentes. portanto não as pode modificar. prt = (double*)malloc(sizeof(double)). Os valores a serem retornados são colocados em referências de variáveis da função chamadora. 5). ptr = new double. int & n1 = n. tranformamos-a em inline. o gerenciamento dinâmico de memória é tão relevante que as palavras new e delete foram incorporadas a linguagem. // toda referência deve ser inicializada informam que n1 é outro nome para n. Marcelo Ricardo Stemmer 126 .13. A diferença básica entre os operadores C++ e C está na confiabilidade e facilidade de uso. A passagem por referência possui as vantagens da passagem de parâmetros por ponteiros. double *ptr. Toda operação em qualquer dos nomes tem o mesmo resultado. Declaração C: Declaração C++ double *ptr. acesso direto a variável fornecida como parâmetro. Exemplo: void reajusta( float& num. Desta forma. este mecanismo possibilita que uma função retorne mais de um valor para a função que chama. reajusta( preco. A principal vantagem da passagem por referência é a de que a função pode acessar as variáveis da função que chamou.Informática Industrial I DAS/UFSC função é pequena e queremos aumentar a velocidade de execução de um programa. } void reajusta( float& num. ponteiros exigem que tenhamos cuidado ao manipular o endereço das variáveis para não causar um erro fatal de acesso a memória.e. O uso mais importante para referências é ao passar argumentos para funções. // Protótipo // Chamada a função // Chamada usando o argumento default float& p) //Definição 4. { num *= p. Em C++. Além desse benefício. void main() { float preco = 10. Quando argumentos são passados por valor. pois não lidamos com o endereço da variável mas sim com uma cópia do seu nome. reajusta( preco).5.4 Operador Unário de Referência: & O operador de referência cria outro nome para uma variável já criada. No entanto. i. a função não tem acessoa às variáveis originais da função qe chamou. não necessitando das conversões de tipo requeridas por malloc(). explicitamente: delete[10] ptr4. o programa deve imprimir na tela todas as fichas feitas. 4. Isto permite que o programador controle como será alocada memória para o seu tipo de dado. Suponha que estamos criando um programa de computador que jogue xadrez contra o usuário.1 Reescreva alguns programas dos exercícios anteriores utilizando agora os novos mecanismos C++ como cout. Primeiramente. Assim. delete ptr1.13. como no problema do arquiteto. se o ponteiro contém um endereço diferente de zero. int * ptr1 = new int. // ou. ptr_tipo = new(tipo). 4. delete[] ptr3. Desenhe todos os elementos do gráfico: título. Analisando-se rapidamente um jogo de xadrez.2 Escreva um programa que desenhe na tela o gráfico da função y = cos(x) + x/2. temos um ambiente a modelar (no caso o jogo de xadrez) e vamos utilizar os componentes deste ambiente para descrevê-lo. o operador new retorna um ponteiro nulo quando a memória disponível é insuficiente. As formas de utilizar o operador new (alocação de memória) e delete (liberação de memória) são: a) como operador ou função ptr_tipo = new tipo. Sempre que uma memória alocada para uma variável não for mais necessária. 13. Analogamente ao que ocorre a função malloc() do C. delete[] ptr4. com passagem de parâmetros por referência. cin e passagem de parâmetros por referência. Marque os pontos pertencentes ao gráfico com o caracter (*). ou seja. Utilize cout e cin para isto. Agora vamos começar a explicar o que são classes e objetos. // ou. delete ptr2.7 Exercícios 13. c) alocação e liberação de matrizes de ponteiros ptr_ptr_tipo = new tipo * [tamanho_matriz].3 Modifique o programa acima para utilizar agoar a alocação dinâmica em C++ e organize agora as fichas por ordem alfabética do nome do paciente. apontamos vários elementos que devem ser modelados.14 Classes e Objetos em C++ No capítulo anterior começamos a apresentar a idéia da Orientação a Objetos em C++. int * ptr3 = new int[10]. Utilize estruturas e funções. O programa deve apenas adquirir os dados e quando o usuário terminar o cadastro. 13. explicitamente: delete[10] ptr3. int * * ptr4 = new int * [10]. linhas horizontal e vertical e numeração. Uma vantagem importante é que os operadores new e delete podem ser sobrecarregados (reimplementados) para um tipo de dado criado pelo programador. Marcelo Ricardo Stemmer 127 . legenda. b) alocação e liberação de matrizes ptr_tipo = new tipo[tamanho_matriz]. devemos sempre verificar se a alocação foi realizada com sucesso.Informática Industrial I DAS/UFSC C++ já fornece um ponteiro para o tipo de dado fornecido. 13. devemos libera-la utilizando o operador delete. Outra vantagem é que C++ define quanto de memória é necessário.2 Crie um programa para fazer cadastro de doentes em um hospital. int * ptr2 = new(int). diminuindo o risco que o programador faça algum tipo de erro. a posição inicial desta peça no tabuleiro. i. definindo as suas propriedades como a cor da suas peças e os seus métodos. Devemos utilizar a primeira representação ou a segunda? Bom. Por exemplo. Está seria uma intuição normal. Podemos em seguida modelar todas as peças do jogo de xadrez. não a motivos para refinar este modelo. o mouse para que o usuário possa mexer as suas peças e todos os demais elementos necessários. Desta forma. Não queremos que o computador jogue contra o usuário. O primeiro é o próprio jogador. Você pode estar achando que terminamos. quantas posições livres existem. Definir esta classe será uma atividade muito mais complexa e “insegura” (no sentido de poder gerar erros) que definir cada tipo de peça isoladamente. definida a classe peão. pois estes são os elementos que vemos quando jogamos xadrez. já teremos então uma representação similar deste.. Por fim. que aqui incluem as suas estratégias de jogo. como esta peça pode ser desenhada na tela. também definimos as relações entre eles. temos múltiplas instâncias do objeto peão. torre. Para cada peça. Todo objeto deve ser modelo a partir da definição da classe que o representa. como uma janela na tela onde desenharemos o tabuleiro. definir métodos para desenhar este tabuleiro na tela e métodos para controlar a posições das peças no tabuleiro. Assim. podemos criar quantas instâncias (objetos) desta classe quanto desejarmos.e. rainha. nesta classe a dimensão da peça de xadrez e o método com que esta deve ser movimentada no tabuleiro vão ser diferentes para cada tipo de peça (peão. de que time pertence (se pertence ao time do computador ou ao time do usuário). Desta forma não teremos uma classe para cada tipo de peça do xadrez mas uma classe que representa todos os tipos de peças de xadrez. tome cuidado para não criar classes desnecessárias. podíamos ter criado somente uma classe entitulada: peças do xadrex. Se o programador desejar ter um controle diferenciado para cada tipo das peças. O bom senso é que define o quanto você deve ou não refinar um modelo. cada objeto peça. Aqui já fica bem clara a idéia do que sejam os objetos no jogo. depende do nível de abstração que desejamos (nível de detalhamento). Outro elemento necessário é uma espécie de juiz. isto é. bispo e cavalo). a cor do tabuleiro. então devemos ter que modelar o jogador.. permitindo assim uma boa estrutura para o programa e capacidade de reutilização. Classes definem tipos de objetos. a cor desta peça e o seu desenho geométrico. O tabuleiro e cada uma de suas peças serão objetos no nosso programa. definimos uma classe chamada peão e definimos nesta classe todos as propriedades e métodos definidos para o elemento peão. podemos modelar cada elemento isolado. rei. Quando modelamos as peças do tipo peão.Informática Industrial I DAS/UFSC Podemos modelar o tabuleiro definindo a suas dimensões. Então. torre. bispo. temos que definir as classes para as demais peças do xadrex como o rei e a rainha. Alguns métodos também são necessários como definir a maneira como esta peça pode ser movimentada no tabuleiro. Mas não podemos esquecer de definir alguns elementos abstratos que estão inseridos no modelo. Adicionamos um índice para podermos referenciar cada elemento peão isoladamente. etc. deveremos definir as propriedades e métodos que segundo esta nossa aplicação podem modelar corretamente o nosso ambiente. Marcelo Ricardo Stemmer 128 . Entretanto. devemos definir algumas propriedades desta como tipo (peão. Para cada um destes elementos. Se o programador achar mais fácil tratar somente um tipo genérico de peça de xadrez.. Descrevendo os componentes do ambiente e a relação entre eles.e.). que o jogo de xadrez já está modelado definindo-se o tabuleiro e as peças. saberá quando é a vez do usuário ou do programador. Cada uma destas peças será um objeto do nosso programa. i. devemos ainda definir alguns elementos necessários para a interface do programa. que controlará as regras do jogo. Quando criamos as classes de objetos. Isto nos leva a ter definições complexas para as atributos e métodos desta classe. então é melhor refinar o modelo e criar uma classe para cada tipo. Desta forma. percebemos que temos vários elementos no nosso ambiente com estas características. ou seja. Mas o que vem a ser as classes do nosso programa. . devemos definir uma classe que controlará a execução do programa. Marcelo Ricardo Stemmer 129 { bas=0. Uma unidade assim é chamada classe. alt=0. Dizemos então que os campos de dados e suas funções estão encapsulados (de cápsula) numa única entidade. manutenção e alteração do programa.14. alt = h. os campos de dados estarão escondidos para nós. são o único meio de acesso aos campos de dados também chamados de variáveis de instância. // atributos publicos // Construtores e Destrutores Retangulo() Retangulo(int a. } { bas = b.14. deve chamar uma função-membro que recebe o valor como argumento e faz a alteração. int h) void PrintData(). } . O exemplo cria uma classe para representar um retângulo. Isso simplifica a escrita. Nenhuma outra função pode acessar esses dados. n++. } { n--. do mesmo modo que a existência do tipo int não cria nenhuma variável inteira.2 Definindo Classes Vamos começar com um exemplo que mostra os elementos básicos na definição de classes e criação de objetos. // Exemplo de uma classe #include <iostream.Informática Industrial I DAS/UFSC Neste capítulo seguimos apresentando a sintaxe para definição de classes de objetos em C++. 4. alt.h> class Retangulo // Define a classe { private: int bas. ~Retangulo() // metodos da classe void Init(int b. Um programa em C++ consiste em um conjunto de objetos que se comunicam por meio de chamadas às funções-membro. Se alguma modificação ocorrer em variáveis de instância de um certo objeto. por funções que não pertençam a classe. // atributos privados public: static int n. Desta forma.1 Tipo Classe e o Encapsulamento de Dados A idéia fundamental de linguagens orientadas a objetos é a possibilidade de combinar num único registro campos que conterão dados e campos que são funções para operar os campos de dados do registro. Devemos evitar o acesso a variáveis de instância diretamente. o que previne alterações acidentais ou inválidas. Definir uma classe não cria nenhum objeto. As palavras encapsular e esconder são termos técnicos da definição de linguagens orientadas a objetos. sabemos exatamente quais funções interagiram com elas: são as funções-membro do objeto. Uma instância (variável) de uma classe é chamada objeto e conterá campos de dados e funções. As funções de um objeto são chamadas funções-membro ou métodos e. por descuido. Se o programa necessita atribuir um valor a alguma variável de instância. O conceito de “esconder” dados significa que eles estarão confinados dentro da classe e não poderão ser alterados. 4. de modo geral. int b=0). cout << "\nArea = " << (bas*alt).3 Membros Privados e Públicos O corpo da definição da nossa classe contém as palavras private e public seguidas de doispontos.Informática Industrial I DAS/UFSC }. A secção pública da classe é formada pelos membros definidos após public: e pode ser acessada por qualquer função-membro e por qualquer outra função do programa onde um objeto foi declarado. // Chama funcao membro de inicializacao X. Podemos. na parte privada da classe são colocados os membros que conterão dados. } // incializacao da variavel estatica int Retangulo::n = 0. 3).14. alt = b. entretanto. Os membros definidos após private: são chamados de parte privada da classe e podem ser acessados pela classe inteira. Este conceito é equivalente à relação existente entre uma função e as suas variáveis locais (auto). Dizemos então que esses dados e funções estarão “escondidos”. Uma definição de classe sempre começa pela palavra-chave class seguida do nome da classe (Retangulo. na parte pública de uma classe são colocadas as funções que irão operar os dados. } void Retangulo::PrintData() // Define funcao membro { cout << "\nBase = " << bas << " Altura = " << alt. Um membro privado não pode ser acessado por meio de um objeto. // Declaracao de objetos Retangulo C[2] = { Retangulo(2. No entanto. Elas especificam a visibilidade dos membros. Retangulo::Retangulo(int a. (C + 1)->PrintData(). Y[0]. Os membros públicos fazem a interface entre o programador e a classe.1) }. de seu corpo delimitado por chaves e finalizado com um ponto-e-vírgula. A primeira tarefa na orientação a objetos é definir as classes.Init( 5. cout << "\n Quantidade de Objetos : " << C[1]. neste exemplo). int b) { bas = a. // Chama funcao membro Y[1]. 4. Geralmente. void main() { Retangulo X(2.PrintData(). } A classe Retângulo possui três atributos e 5 funções.3). Agrupar dados e funções numa mesma entidade é o fundamento da programação orientada a objetos. Retangulo Y[5]. pode-se colocar também funções que só poderão ser chamadas por outras funções da própria classe. mas não fora dela. Retangulo(5. elas não são visíveis fora da função. Geralmente. Marcelo Ricardo Stemmer 130 .PrintData(). n++.n.3). entretanto estes dados poderão ser acessados diretamente pelos objetos desta classe. Quando um objeto da classe Retangulo é criado. int b=0).5 Construtores & Destrutores Muitas vezes é conveniente inicializar um objeto (instância da classe) quando ele é criado.14. Init(int. mas foram definidas fora dela. não poderemos controlar o acesso a este dado da classe. No nosso exemplo. contanto que o seu protótipo seja escrito dentro do corpo da definição da classe. alt=0.Informática Industrial I DAS/UFSC colocar dados na parte pública da classe. definir funções-membro em algum lugar do programa fora da classe. os dados bas e alt tem acesso privado. } 4. enquanto que o dado n e todas as funções tem acesso público. Funções-membro de código definido dentro da classe são criadas como inline por default. o construtor Retangulo() foi definido dentro da classe enquanto que o construtor Retangulo(int. Isto informa ao compilador que elas fazem parte da classe. Esta função-membro é conhecida como construtor.14. A inicialização automática de um objeto é efetuada por meio da chamada a uma função-membro especial quando o objeto é criado. ~Retangulo(). definimos a função PrintData()fora da classe. Retangulo(int. também chamadas métodos. é que declaramos um construtor. No nosso exemplo. int) e PrintData(). int). Observe que na definição destas funções membro. int b) { bas = a. Este operador é o meio pelo qual informamos ao compilador que a função sendo definida está associada àquela classe particular. Este símbolo é chamado operador de resolução de escopo. tornando a execução desta mais rápida mas ocupando um espaço maior de memória para armazenar o programa. Por isso. n++. Observe que um construtor não deve retornar valor nenhum. n++. Então. o operador de resolução escopo informa que a função PrintData() é membro da classe Retangulo. 4. int) foi definido fora desta. Podemos.4 Funções-Membro Funções-membro. sem nenhum tipo. ficando claro na definição que um construtor não retorna nenhum tipo de dado. alt = b. Marcelo Ricardo Stemmer 131 . sem necessidade de efetuar uma chamada a função-membro para que os dados sejam inicializados. o nome da função é precedido pelo nome da classe (no caso: Retangulo) e por um símbolo formado por dois caracteres de dois-pontos (::). entretanto. Na classe Retangulo. a definição completa fica: Retangulo::Retangulo(int a. Um construtor é uma função-membro que tem o mesmo nome da classe e é executada automaticamente toda vez que um objeto é criado. são as que estão dentro da classe. Sendo assim. definimos 5 funções-membro: Retangulo(). No exemplo acima. int) recebe como parâmetro dois números inteiros e têm seu código definido dentro da definição da classe. chama-se automaticamente o construtor da classe para inicializar os dados desta. Observe que a função Init(int. } Retangulo(int a. nas instruções : Retangulo() { bas=0. No nosso exemplo. Estas funções executam operações comuns em classes: atribuem valores aos dados e imprimem certos resultados. O motivo é ele ser chamado diretamente pelo sistema e portanto não há como recuperar um valor de retorno. permitindo assim que o usuário precise fornecer somente o primeiro parâmetro. 4. elementos delimitados por chaves. quando criamos uma matriz de objetos de uma classe. A primeira instrução cria um objeto da classe Retangulo chamado X. separados por vírgulas e o fim da instrução definido pelo (. o programa utiliza o construtor default para criar todos os objetos juntos e inicializar todos com este construtor. int) para explicitamente fornecer os valores iniciais para os dados da classe. No nosso exemplo fica clara esta aplicação. A segunda instrução cria uma matriz unidimensional de objetos da classe Retangulo. exceto pela falta de tipo.3). os destrutores não podem ter valor de retorno. pode ser definido passando-se como parâmetro do construtor o objeto que desejamos copiar. O compilador decide qual construtor chamar de acordo com os parâmetros passados. criamos objetos da classe Retangulo através das instruções: Retangulo X(2. é chamado de construtor default.14. O seu código é igual ao de qualquer outra função. Este conceito é idêntico ao das estruturas que. o construtor default é empregado para a inicialização dos objetos.6 Criando Objetos Após a definição da classe Retangulo. A terceira instrução cria um matriz unidimensional de objetos da classe Retangulo. utilizado para iniciar um objeto como sendo uma cópia fiel de um objeto já existente. então com certeza o construtor default será utilizado. somente o descreve. No nosso exemplo. Aplicando no nosso exemplo. // Declaracao de objetos Retangulo C[2] = { Retangulo(2. ou utilizar o construtor Retangulo(int. Note que a inicialização de matrizes de objetos mantém o formato anterior. Declarar um objeto é similar a declarar uma variável de qualquer tipo. O construtor Retangulo() tem um importância imensa em C++. teríamos: Retangulo(Retangulo Ret). não criam nenhuma variável. int). Desta forma. Marcelo Ricardo Stemmer 132 . podemos declarar uma ou mais instâncias desse tipo. Observe que a definição da classe não cria nenhum objeto. Não é interessante ter que inicializar cada objeto individualmente. Podemos sobrecarregar construtores para podermos criar objetos de forma diferenciada.3). ou seja. Outro elemento importante é o construtor de cópia. se nenhum outro construtor puder se utilizado (nenhum dado pode ser fornecido).) ponto-e-vírgula. cada classe possui somente um construtor) nem pode ser chamado explicitamente pelo programador. podemos sempre garantir uma inicialização dos dados com o construtor default. } Da mesma forma que um construtor. Retangulo(5. inicializando-o como o construtor Retangulo(int. Uma instância de uma classe é chamada objeto. Uma função destrutora é chamada automaticamente toda vez que um objeto é destruído (liberado da memória) e tem o mesmo nome da classe precedido de um til (~): ~Retangulo() { n--. Este operador. Por exemplo.1) }. quando definidas. Neste caso. Podemos utilizar o construtor Retangulo() para inicializar o objetos com dados default.Informática Industrial I DAS/UFSC Um construtor pode perfeitamente chamar uma função-membro. Sempre que um objeto for criado. Note que este segundo construtor faz uso de valores default para os parâmetros. O destrutor também não pode receber argumentos (por isso. Por isso. como já mencionamos anteriormente. Retangulo Y[5]. A matriz é inicializada com um conjunto de objetos Retangulo. o espaço de memória é reservado. toda vez que criarmos um objeto desta classe. alocando memória para esta. se não. não importando o número de objetos declarados. Funções podem ser definidas como static. cin >> US. Marcelo Ricardo Stemmer 133 . a utilizamos para contar o número de objetos criados. ou seja. chamamos o seu construtor que incrementará automaticamente n. public: static void usvalor() { cout << “\nDigite o valor do dólar: ”. Funções static podem ser chamadas usando a mesma sintaxe utilizada para acessar dados static. No programa exemplo. Desta forma. Funções-membro static agem independentemente de qualquer objeto declarado. Se destruirmos um objeto. da seguinte forma: int Retangulo::n = 0. Nesta declaração. mostramos a declaração de um membro static com visibilidade pública da classe Retangulo. podemos efetuar a inicialização desta variável. Funções membro static acessam somente membros static de classe. Você pode considerar que a definição de um atributo da classe como static. Note que cada vez que criamos um objeto. Observação: um dado do tipo static não pode ser inicializado no construtor de uma classe pois.7 Atributos do Tipo Static Cada objeto de uma classe possui a sua própria cópia dos dados da classe. Note que a palavra chave static não foi empregada e que utilizamos Retangulo:: para indicar que n pertence a classe Retangulo. tendo a mesma visibilidade de um membro normal da classe.14. Abaixo. Conseqüentemente. Quando um dado membro é declarado como static. só pode ser acessado através desta classe. Este item faria o mesmo papel de uma variável externa. Funções static têm características similares as variáveis static.Informática Industrial I DAS/UFSC 4. Entretanto. class moeda { private: static float US. } }. como apresentado acima. n conta automaticamente o número de objetos existentes de uma certa classe. A declaração desta variável fora da classe é que irar realmente criar esta variável. Este tipo de variável pode ser bem útil. muitas vezes desejamos que todos os objetos de uma classe tenham acesso um mesmo item de dado. Dados static devem ser obrigatoriamente redefinidos fora da definição da classe. static int n. Um membro static é definido com um atributo qualquer da classe. chamamos o seu destrutor que irá decrementar n. é criado um único item para a classe como um todo. estaremos reinicializando o valor desta variável static para todos os demais objetos. estas funções não podem acessar nenhum membro não-static da classe. Isto significa que o programa alocou somente um espaço de memória onde todos os objetos desta classe irão acessar este dado. simplesmente notifica o compilador que existe um variável global (extern) que será utilizados por todos os objetos desta classe para armazenar este atributo. A informação de um membro static é compartilhada por todos os objetos da mesma classe. porém será visível somente a todos os objetos daquela classe. moeda::usvalor(). Esta declaração é feita em qualquer lugar fora da classe. São utilizadas para implementar recursos comuns a todos os objetos da classe. para podermos utilizála junto com o objeto X: class Retangulo { void PrintData() const. Quando um objeto constante é declarado. Portanto. Ao definir esta variável fora da classe. }. Entretanto. vamos transformar a função PrintData() em const. No nosso exemplo. int) do primeiro objeto da matriz Y: Y[0]. acessando a função Init(int. estaremos indicando que a função não modifica o objeto.3).14. Como ‘n’ é uma variável global (static) associada à classe Retangulo. Desta forma é possível acessá-la a partir de um objeto const. podemos acessar este dado sem associá-lo a nenhum objeto ou até mesmo. // Chama funcao membro Note que podemos utilizar este operador para acessar dados públicos: cout << "\n Quantidade de Objetos : " << C[1].9 Objetos Const O qualificador const na declaração de um objeto indica que o objeto é uma constante e nenhum de seus dados pode ser alterado. ou seja.Init( 5.n. 4.Informática Industrial I DAS/UFSC 4. a instrução abaixo cria X como um objeto constante.PrintData(). 3). pois não consegue identificar quais funções alteram os seus dados. Y[1].14. As funções-membro só podem ser chamadas quando associadas ao objeto específico pelo operador ponto. Marcelo Ricardo Stemmer 134 . há um modo de informar ao compilador que uma função-membro não altera nenhum dado do objeto e que poderemos chamá-la por meio de um objeto constate. A sintaxe é similar à de acesso aos membros de estrutura. acessando a função PrintData(): X. A palavra const deve ser adicionada tanto no protótipo da função quanto na sua declaração. Por exemplo. Por exemplo.n == Retangulo::n O operador (->) pode ser utilizado quando tempos um ponteiro para um objeto e queremos acessar um membro (dado ou função) público desta classe. Para acessá-la.PrintData(). Uma função-membro age sobre um objeto particular e não sobre a classe como um todo. ambas instruções abaixo são equivalentes: C[1]. no caso de variáveis static. os dados de X não podem ser alterados em tempo de execução: const Retangulo X(2. nos já alocamos memória para ela fosse inicializada. sem nunca ter criado um objeto desta classe. // Chama funcao membro de inicializacao Aqui. empregamos este operador na instrução abaixo: (C + 1)->PrintData(). Nosso programa fornece algums exemplos deste tipo de acesso: Primeiro. basta utilizar o operador (::) para referenciar a classe associada a esta variável. Ao colocar a palavra const após os parênteses que envolvem a lista de parâmetros da função.8 Acessando Funções e Dados Públicos Os membros públicos de um objeto são acessados por meio do operador ponto. o compilador proíbe a ele o acesso a qualquer função membro. Imprima na tela usando cout. O resultado da ação de cada uma das funções da família é o mesmo. Controle a lotação do estacionamento e verifique se existem vagas disponíveis. C++ saberá identificar qual é a função com o código adequado ao contexto. 14.5 Modelo o problema do jogo do xadrez apresentado no início do capítulo. Como exemplo. Modele cada aluno com o seu conjunto de notas como sendo uma classe. uma nova região na memória é alocada de forma que cada objeto possui o seu conjunto de dados.14. os que ganham por comissão. pedir a lista de clientes e a lista de fitas ou alterar algum parâmetro destas. para cada objeto declarado. Armazene dados importantes do carro como chapa do carro. crie um programa para representar restaurantes empregando uma lista ligada construída com classes.4 Escreva um programa para controlar o acesso das vagas de um estacionamento.10 Tipo Objeto Objetos de classes podem ser usados normalmente como qualquer outro tipo de dado. 14. Criamos um conjunto de funções em que cada uma tem um método diferente de calcular o salário. Mas não jogue contra o computador mas contra um outro usuário usando o mesmo micro. chamamos de polimorfismo a criação de uma família de funções que compartilham do mesmo nome. As funções membro são criadas e colocadas na memória somente uma vez para a classe toda. fazer uma pesquisa. cout << "\nArea = " << (bas*alt). quando o usuário retirar o carro. A maneira de atingir esse resultado é distinta. mas cada uma tem código independente.Informática Industrial I DAS/UFSC void Retangulo::PrintData() const // Define funcao membro { cout << "\nBase = " << bas << " Altura = " << alt. 4. a hora de entrada.15 Sobrecarga de Operadores O sentido do polimorfismo é o de um único nome para definir várias formas distintas. As funções membro são compartilhadas por todos os objetos da classe. Marcelo Ricardo Stemmer 135 . } 4. Nessa empresa.14. 14. etc.3 Crie um programa que faça o controle de cadastro de usuários e controle de alocação para uma locadora de fitas de vídeo. Não esqueça que alguns clientes podem ficar mais tempo do que o tempo notificado. O usuário de poder incluir/retirar um cliente ou uma fita. No caso dos dados.2 Usando a idéia da lista ligada apresentada capítulo de estruturas. O programa deve gerar automaticamente o preço do estacionamento. Quando a função é chamada. da mesma forma que fazemos com outros tipos de dados.11 Exercícios 14.1 Crie um programa para calcular a média das notas dos alunos de uma turma. suponhamos que desejemos calcular o salário líquido de todos os funcionários de uma empresa. e emprege o método da lista ligada para gerenciar um vetor dinâmico. Em C++. Por isso podemos utilizá-los para definir matrizes de objetos ou para passar como parâmetro. 4. mensalistas. a hora de saída. há horistas. Utilize uma classe para os clientes e outra para as fitas. 14. tomemos o operador aritmético (+). que tenhamos definido a seguinte função que executa a operação (a + b) : int soma(int a. Note que a única diferença na declaração ou definição de um operador é que o nome de um operador é definido pela palavra chave operator seguida de espaço mais o símbolo que representa o operador. A = A + B. neste caso (+). com a sobrecarga do operador (+) poderemos redefinir a seguinte função para dois elementos da nossa classe: complexo A. os operadores podem ser sobrecarregados para outras aplicações. Marcelo Ricardo Stemmer 136 . Por isso. qual a razão da sua existência? Suponha. permitindo que este possa definir como os operadores existentes em C++ atuarão com relação aos tipos de dados definidos pelo programador. Note que esta definição é bem intuitiva e clara.7 + 12. é vista por C++ como uma chamada a função acima declarada. C++ utilizará a definição desta função para efetuar a operação. Quando escrevermos em nosso código esta operação. int c = a + b. Então. C++ interpreta esta instrução como uma chamada a função operator + e passa para esta os parâmetros a e b.Informática Industrial I DAS/UFSC A sobrecarga é um tipo particular de polimorfismo. Assim como qualquer outra função em C++.e. i. Por exemplo. onde o nome da função é o símbolo do operador e os parâmetros da função são os operandos do operador. o operador de soma para números inteiros possui uma declaração do tipo: int operator +(int a. A utilização de um mesmo símbolo para a execução de operações distintas é chamada “sobrecarga”. chamada complexo. Assim. usamos esse operador para somar números inteiros ou para somar números reais: 5 + 4 3. Somente os operadores já existentes em C++ podem ser sobrecarregados (redefinidos) para operar sobre novos tipos de dados definidos pelo programador. Qual das duas formas abaixo é mais clara e intuitiva para se escrever a soma de dois números? int c = soma( a. b). Como exemplo. a operação (a+b). Suponha que tenhamos criado uma classe para representar os números complexos. Os operadores em C++ são definidos como funções normais.5 O computador executa operações completamente diferentes para somar números inteiros e números reais. Esta característica é muito importante para o programador. pois este símbolo não é declarado por C++ como sendo um operador.. podemos redefinir os operadores para serem empregados em outros tipos de dados criados pelo programador. B. Ou seja. int b). Em C++. O polimorfismo e a sobrecarga são habilidades únicas em linguagens orientadas a objetos. int b). É claro que será a segunda forma. Por exemplo. podemos tornar o nosso código-fonte muito mais organizado e claro empregando-se os operadores ao invés de funções normais. quando escrevemos no código (a+b). Se os operadores são tratados por C++ como uma função qualquer. Perceba que. não podemos definir o símbolo (#) como um operador. podemos tratar qualquer operador como sendo uma função normal mas que possui um nome especial e uma forma especial de chamada. por definição.'<< Y <<')'.h> class Ponto { public: int X.2). retornando o próprio objeto passado como parâmetro com o resultado da operação. cout << "\n++p1 = ".PrintPt(). este é um operador unário e. possui dois atributos com acesso publico. O operador recebe somente um parâmetro. A seguir vamos apresentar a sobrecarga do operador ++() incremento prefixado para a classe Ponto. contém as coordenadas x e y do ponto.X. mas de códigos de programa diferentes. O operador recebe como parâmetro um objeto da classe Ponto e retorna também um objeto desta classe. pode mudá-los conforme as suas necessidades. de maneira que ele se aplique também a tipos de dados definidos pelo usuário como classes e estruturas. Sobrecarregamos o operador ++() para incrementar os dados contidos em um objeto desta classe. (++P1). uma função construtora para inicializar os atributos e uma função para imprimir os dados na tela. No instante em que você encontrar uma limitação pelo modo como os operadores C++ trabalham. cout << "\n p1 = ".Y. } void PrintPt() const {cout << '(' << X << '. int aY = 0) { X = aX. } A classe Ponto é uma classe normal.0 A Sobrecarga como uma Função Global A implementação de sobrecargas de operadores é definida por meio de funções chamadas operadoras. acessíveis a todo o programa.Mostra a sobrecarga de operadores #include <iostream. por meio de sobrecargas.PrintPt(). Note que o operador é declarado como qualquer função global.} }. //Ponto2 . só pode receber um único parâmetro. ++ObjPonto. O operador acessa os dados públicos da classe Ponto e incrementa cada um deles. Ponto operator ++(Ponto ObjPonto) //incremento prefixado { ++ObjPonto. Após a declaração da classe. pois no caso. Várias funções com o mesmo nome podem apresentar diferentes implementações (trechos de programa). Y. Estas funções podem ser criadas como membros de classes ou como funções globais. 0.0. P1.Informática Industrial I DAS/UFSC Sobrecarregar um operador significa redefinir o seu símbolo. a única diferença é a palavra-chave operator na frente do símbolo ++. criada para representar um ponto localizado no espaço bidimensional e que. Y = aY. Marcelo Ricardo Stemmer 137 . por esta razão. Ponto(int aX = 0. return ObjPonto. Sobrecarregar uma função significa utilizar um mesmo nome para tarefas parecidas. } void main() { Ponto P1(1. segue a declaração do operador. . temos que definir que esta operação retorna algum valor do tipo da variável c. os operadores binários operam sobre dois operandos (+. Devemos limitar-nos aos operadores já existentes. o operador de multiplicação (*) tem precedência sobre o de adição (+). não se pode inventar uma operação usando o símbolo ##.0 Limitações e Características A sobrecarga de operadores permite uma nova implementação da maneira como um operador funciona. >. Por outro lado. Por exemplo. Uma função operadora deve ter definido um tipo de retorno. #include <iostream.h> class Ponto { private: int X.15. Entretanto. Os seguintes operadores não podem ser sobrecarregados: o operador ponto de acesso a membros e o operador condicional ternário (?:). Nem todos os operadores podem ser sobrecarregados. os operadores unários receberão um único parâmetro enquanto que os operadores binários receberão dois parâmetros. Quando definimos um operador como sendo uma função-membro de uma classe. 4. uma atenção especial deve ser dada ao uso de cada tipo. apresentamos a declaração do operador de incremento pré-fixado redefinido globalmente. Marcelo Ricardo Stemmer 138 . +=. Declarar um operador como sendo membro de uma classe. decremento (--) e menos unário (-). é necessário respeitar a definição original do operador.Informática Industrial I DAS/UFSC Em seguida. já que o primeiro operando é sempre um objeto da classe. Exemplos de operadores unários são o de incremento (++). apresentada no próximo capítulo. -.4 Sobrecarga de Operadores como Função-Membro No exemplo anterior. Por causa desta diferença. Já na declaração de operadores como funções-membro de uma dada classe. Este símbolo não é um operador válido em C++ e você não poderá torná-lo um operador. não é possível mudar um operador binário (que trabalha com dois operandos) para criar um operador unário (que trabalha com um único operando). permite que este tenha acesso a todos os dados desta classe. /. tenha as permissões de acesso como qualquer outra função membro e possa desfrutar das vantagens fornecidas pela herança de classes. *. Não é permitido também estender a linguagem inventando nossos operadores representados com símbolos novos. Por exemplo. o primeiro parâmetro passado para a função operadora será considerado automaticamente como sendo um objeto desta classe. Y. empregamos o novo operador incrementando o objeto P1 e imprimindo na tela o resultado gerado por este operador. para poder executar a seguinte instrução: c = a + b. 0. redefinir este operador com uma função-membro da classe Ponto. Vamos agora.). Na declaração de operadores como funções globais. os operadores binários não receberão parâmetros enquanto que os operadores binários receberão um único parâmetro.0.. para que o resultado da operação com este tipo possa ser atribuído a outras variáveis. etc. Por exemplo. Não é possível modificar a precedência de operadores por meio de sobrecargas. Os operadores unários operam sobre um único operando. ao definir o operador (a+b). Por exemplo. A definição de operadores deve obedecer à precedência original do operador. Y = aY. } Neste exemplo. P2. int aY = 0) { X = aX. P2 = ++P1.Informática Industrial I DAS/UFSC public: Ponto(int aX = 0. A definição da função é praticamente igual a anterior. Com este exemplo. Note na função main(). Por fim. A função operadora ++() agora cria um objeto temporário da classe Ponto para conter o resultado da operação e ser utilizado como retorno da função.} Ponto operator ++() //incremento prefixado { ++X. a manipulação de matrizes em C++ apresenta várias falhas e permite erros acidentais de sobreposição de dados de memória se forem usados índices que ultrapassam o limite de dimensão da matriz. Veremos a seguir. Por causa disto. Por isso. Marcelo Ricardo Stemmer 139 . 4. que o emprego do operador não sofreu nenhuma modificação pelo fato deste ser declarado como uma função global ou uma função membro. O primeiro exemplo cria uma classe para armazenar as notas dos alunos. cout << "\n++p1 = ".5 Estudo de Casos Agora apresentaremos a sobrecarga de um grupo importante de operadores em C++ que servirão como exemplo para a sobrecarga de qualquer outro operador existente.PrintPt().'<< Y <<')'. cout << "\n++p2 = ".15. efetuamos algumas modificações importantes. discutiremos outros aspectos da sobrecarga e você perceberá também a utilidade desta ferramenta. A sobrecarga de dois operadores foi efetuada. Esta função é uma função inline da classe Ponto. (++P2). note que agora esta função não recebe nenhum parâmetro. podendo ser empregados facilmente para outras aplicações.Y). não podendo mais ser acessados por nenhuma função global. Ponto Temp(X. cout << "\n p1 = ".3). converterá um objeto da classe Matriz para um ponteiro float. por esta definida dentro da definição da classe.PrintPt(). } }. } void PrintPt() const {cout << '(' << X << '. nada foi modificado no emprego do operador sobrecarregado.PrintPt(). Sobrecarregamos o operador incremento prefixado como sendo uma função-membro da classe Ponto. formas diferentes de retornar o resultado de uma função operadora. passaram a ter acesso privado. P1. return Temp. efetuamos a sobrecarga do operador [] para testar o limite da matriz. Isto torna os objetos desta classe mais genéricos. C++ não faz a checagem de limites de matrizes. P2(2. cout << "\n p2 = ". void main() { Ponto P1. retirando-se o parâmetro. ++Y. Os dados da classe Ponto.PrintPt(). (++P1). O outro operador. cout << setprecision(2). float & operator [](int i). operator float *() const // Funcao Conversora { return (float *)n. cin >> Notas[i]. }while (Notas[i++] >= 0). i<MAX. } void main() { Matriz Notas. int i = 0.0. } Marcelo Ricardo Stemmer 140 . else { cout << "\nFora de Limite!". } float & Matriz::operator [](int i) { static float x = -1.h> #include <iomanip. Matriz::Matriz() { for(int i = 0. class Matriz { private: float n[MAX]. i++) n[i] = 0. for(int j = 0. return m/float(i).Informática Industrial I DAS/UFSC //Notas : Sobrecarga do operador [] #include <iostream. j++) m += n[j]. // sobrecarga [] float Media(int i). i--. cout << "\nNota do Segundo Aluno " << *(Temp + 1). do { cout << "Digite a nota do aluno " << (i + 1) << " : ".Media(i).h> const MAX = 50. if(i >= 0 && i < MAX) return n[i]. } } float Matriz::Media(int i) { float m = 0. float * Temp = Notas. j < i. public: Matriz(). cout << "\n\nMedia das notas : " << Notas.0. } }. return x. o valor de todos os seus membros de dados são simplesmente copiados no novo objeto. recebe um único parâmetro int i. Se não estiver. Caso contrário.141567). Retornar uma referência não é simplesmente eficiente. quando o valor de um objeto é atribuído a outro de mesma classe. podendo ser usado em instruções como : cin >> notas[i]. Dessa forma. O compilador não executa nenhuma instrução especial no uso de atribuições entre tipos definidos pelo usuário. podemos também converter um objeto de uma classe em um tipo básico ou em um objeto de outra classe. A função é definida fora da classe. Por isso. Marcelo Ricardo Stemmer 141 . Geralmente. pois não podemos retornar uma referência para uma variável local (automática) já que esta será destruída ao final da execução da função. A função operator [] cria uma variável static. notas[i] = 67.75. No exemplo anterior. Assim como podemos converter um tipo básico em outro tipo. que poderia ter sido escrita na forma explícita: float * Temp = float *(Notas). Se estiver. Isto previne a sobreposição de outras regiões da memória caso o limite da matriz seja ultrapassado. imprimindo a média das notas no final. como classes. a função retorna uma referência ao elemento correspondente da matriz privada. criando uma função chamada conversora. para converter um objeto desta classe em um ponteiro para uma lista de valores float: operator float *() const // Funcao Conversora { return (float *)n. Você sabe que o operador = pode atribuir o valor de uma variável simples a outra do mesmo tipo. não teremos acesso direto a um elemento da classe mas a uma cópia deste. a função imprime uma mensagem de erro e retorna uma referência a uma variável static float com valor –1. Para converter um tipo definido pelo programador. num tipo básico é necessário sobrecarregar o operador de mold. Podemos também atribuir um objeto a outro da mesma classe usando instruções como: Obj2 = Obj1. A novidade é a função operator[] que checa se o índice especificado está dentro do limite de dimensionamento da matriz. sobrecarregamos o operador float *() como sendo uma função da classe Matriz. } Este operador foi chamado pela instrução: float * Temp = Notas. mas sim necessário. int i = (int) 3.Informática Industrial I DAS/UFSC O programa cria uma matriz fixa para armazenar as notas dos alunos. e por isso escrevemos Matriz:: antes do nome operator []. A complexidade surge quando a atribuição é entre variáveis de tipos diferentes. não podendo assim alterar o valor deste elemento com instruções de atribuição como as declaradas acima. Podemos converter um valor float para uma variável inteira através de uma das seguintes instruções: int i = int(3. para indicar que se trata de uma função membro. Aqui começamos a discutir alguns aspectos sobre o operador de atribuição (=).141567. a expressão notas[i] age como o próprio elemento da matriz privada. A função operator [] sobrecarrega o operador binário [] e está definida dentro da classe Matriz. Observe que a função operator [] retorna uma referência a um elemento da matriz n. Y += aN.X. ++Y. return *this. Y-1). o próprio nome da função já define o tipo de retorno. então o compilador procura pela função conversora para este tipo. Ponto(int aX = 0. Y. exemplo da sobrecarga de operadores #include <iostream. }. bool operator ==(Ponto const aP) const.Y)). // Classe Ponto . se não encontra. ++Y. para apresentar outras características e exemplos da sobrecarga de operadores. Y = aY. Primeiro o compilador procura pela sobrecarga da operação de atribuição =() para este tipo.. // pos-fixado Ponto operator +(Ponto const aP) const. } Ponto Ponto::operator +=(int const aN) { X += aN. No próximo exemplo vamos adicionar um conjunto de operadores a classe Ponto definida anteriormente. } Ponto Ponto::operator =(int aN) { X = aN.Y). int aY = 0) { X = aX. return *this. } Marcelo Ricardo Stemmer 142 . true }. Ponto operator =(int aN)..Informática Industrial I DAS/UFSC As duas formas têm exatamente o mesmo efeito. } Ponto Ponto::operator ++(int) //pos-fixado { ++X. Ponto Ponto::operator ++() //prefixado { ++X. Ponto operator +=(int const aN). class Ponto { public: int X. } Ponto operator ++(). return Ponto(X-1. } Ponto Ponto::operator +(Ponto const aP) const { return Ponto(X + aP. // prefixado Ponto operator ++(int).X)&&(Y == aP. Note que a função conversora não declara um tipo de retorno. } bool Ponto::operator ==(Ponto const aP) const { return ((X == aP.h> enum bool { false. Y + aP. return *this. '<< aP. Dentre os operadores unários existentes em C++. Y). P2(2. // Operadores para objetos Iostream ostream & operator<<(ostream & OS. return Temp( X. (int) Y). para representar os valores booleanos. float aY = 0) { X = aX. cout << "\n p3 = " << P3.Informática Industrial I DAS/UFSC class PFloat { public: float X. P3. Y. 3. cout << "\n p2 + p1 = " << (P2+P1). A classe Ponto possui agora os atributos X e Y como sendo dados públicos. cout << "\n ++p1 = " << ++P1. Os primeiros operadores sobrecarregados no exemplo são os operadores unários de incremente pré-fixado e pós-fixado. somente para facilitar o acesso a estas variáveis.X << '. A segunda diferença esta na forma como retornamos o resultado da operação. A primeira diferença é que a agora é operador está definido fora da definição da classe.3). cout << "\n p2 = " << P2.14). cout << "\n p2 == p1 ? -> " << (P1 == P2). cout << "\n p1 = " << P1. Podemos faze-la de três formas: a) Ponto Temp( X. Ponto possui também um construtor default para a inicialização dos dados. Ponto const aP) { OS << '(' << aP. A definição do operador é idêntica a definição apresentada anteriormente. } }. return Temp. Y = aY. Y). P3 = 2. A declaração : Ponto operator ++(). } Começamos definindo um tipo enum. PFloat Pf( 2. // prefixado notifica o compilador da sobrecarga do operador prefixado. P1 = Pf. 143 b) Marcelo Ricardo Stemmer . cout << "\n pf = " << Pf.Y <<')'.12. PFloat(float aX = 0. a sobrecarga dos operadores de incremento e decremento apresenta uma dificuldade maior pelo fato de eles operarem de forma diferente quando prefixados ou pós-fixados. } operator Ponto() const // Converte tipo { return Ponto((int) X. } void main() { Ponto P1. desde que em cada definição tenha um tipo de dado diferente como operando. Este parâmetro int não serve para nada. temos a definição dos operadores binários aritméticos (+) e (+=). armazenam nele os valores obtidos na operação e retornam este objeto temporário. é de responsabilidade puramente do programador. redefinir um operador lógico para efetuar uma operação aritmética ou qualquer outra operação entre dois objetos. como foi dito anteriormente. sendo que ambos utilizam o mesmo símbolo e possuem o mesmo operando? Neste caso. Isto ocorre por que no operador pós-fixado. Seguindo com o nosso exemplo. já que o operador é do tipo lógico. Um operador binário definido como uma função-membro possuirá somente um parâmetro. temos a sobrecarga do operador binário lógico (==) . Quando um objeto é criado. o compilador atribui o endereço do objeto ao ponteiro this. o próximo operador definido é um operador de atribuição (=). Uma classe pode redefinir várias vezes os operadores binários. Depois. Qualquer função-membro pode acessar o endereço do objeto do qual é membro por meio do ponteiro this. não podemos utilizar a passagem de parâmetros por referência pois estes objetos temporários serão destruídos ao término da função. No exemplo. C++ somente não permite a criação de novos operadores e solicita que o número de parâmetros definido para cada operador seja respeitado. C++ adicionou um parâmetro inteiro ao operador de incremento pós-fixado. Mas como pode o compilador distinguir os dois. O tipo de retorno aqui é um tipo booleano (inteiro). a não ser para podermos distinguir a declaração dos dois tipos de operadores. este recebe um único parâmetro. Usamos o ponteiro this quando queremos que uma função-membro retorne o próprio objeto do qual é membro. agora não podemos utilizar o ponteiro this para retornar o próprio objeto mas temos que criar um objeto temporário que conterá o valor a ser retornado. O operador (+) cria um objeto temporário para conter o resultado enquanto que o operador (+=) utiliza o ponteiro this para retornar o próprio objeto como resultado. Entretanto. por exemplo. O ponteiro this é um ponteiro especial que pode ser acessado por todas as funções-membro do objeto. Por isso. retornando um valor do tipo inteiro. enquanto que o operador (+=) implementa a soma de um valor inteiro a um objeto da classe Ponto. possuindo a seguinte declaração: Ponto operator =(int aN). // pos-fixado Observe que esta função operadora é definida como a anterior. As duas primeiras formas criam um objeto temporário. que no caso será outro objeto da classe Ponto. o operador (+) implementa a soma de dois objetos da classe Ponto. armazenando o resultado no próprio objeto. Este ponteiro aponta para o próprio objeto. somente poderá ser sobrecarregado para efetuar operações lógicas entre objetos. primeiro nós utilizamos a variável para depois incrementá-la. Podemos. é que declaramos este operador da seguinte forma: Ponto operator ++(int).Informática Industrial I DAS/UFSC c) return *this. Marcelo Ricardo Stemmer 144 . Neste caso. Como os operadores acima. definimos o operador de incremento pós-fixado. C++ não controla a maneira como utilizamos os operadores com os novos tipos de dados. O programador tem liberdade em C++ para definir a aplicação que será dada para um operador. Para retornar o próprio objeto. utilizado para atribuir um inteiro a um objeto do tipo Ponto. O terceiro utiliza o ponteiro especial this. Não significa que um operador lógico. Por exemplo. Em seguida. devemos utilizar *this. um programador pode sobrecarregar um operador binário de bis (^=) para atuar como um operador lógico ente objetos de uma dada classe. Após o operador de incremento prefixado. para distingui-lo do prefixado. O que o operador faz. Em especial.Y. // Operadores para objetos Iostream ostream & operator<<(ostream & OS. Como vimos nos capítulos anteriores. criamos a classe PFloat parecida com a classe Ponto. Note que a forma de declarar e definir o operador é a mesma utilizada nos exemplos acima. A novidade surge na declaração do operador de conversão para objeto da classe Ponto: operator Ponto() const // Converte tipo { return Ponto((int) X.X. utilizávamos a função PrintPt() para imprimir o valor de um objeto desta classe na tela. para exemplificar a conversão de objetos de uma classe em objetos de outra classe. A mesma sintaxe pode ser aplicada para converte qualquer tipo de objeto em uma outra classe. Entretanto. a classe istream controla a entrada padrão e a classe ostream controla a saída padrão. podemos fazer isto de uma forma muito mais elegante definindo o operador << para receber como operandos um objeto da classe ostream e um objeto da classe Ponto. Ponto const aP) { Marcelo Ricardo Stemmer 145 . possui também um construtor default. mostramos como podemos criar uma função conversora para converter um objeto de uma classe em outra classe. Esta é uma das formas importantes para converter um tipo em outro. 1) Sobrecarregando o operador de atribuição da classe Ponto. Em seguida. sobrecarregamos o operador global de inserção de dados em objetos da classe ostream. Lembrando. as classes stream controlam o acesso a entradas e saídas do computador.} O resultado desta conversão aparece na execução da seguinte instrução: P1 = Pf. e aparece quando executamos a seguinte instrução e atribuímos 2 ao objeto Ponto P3: P3 = 2. Por fim. } No exemplo anterior apresentamos a conversão de um objeto da classe Matriz para um ponteiro do tipo float. Esta classe. para atribuir um objeto da classe PFloat em um objeto da classe Ponto. Este operador também utiliza o ponteiro this para retornar o próprio objeto. Poderíamos também implementar esta conversão de outras duas formas diferentes. Y =(int)P. Note que PFloat contém as coordenadas de um ponto x e y com valores float.Informática Industrial I DAS/UFSC O operador atribui a dimensão X do objeto ponto o valor de aN. que receba como único parâmetro um objeto da classe PFloat: Ponto::Ponto(PFloat P1) { X =(int)P. A novidade aqui aparece quando utilizamos este operador para converter um inteiro em um objeto do tipo Ponto. chamando automaticamente as funções de leitura e escrita da classe stream através da sobrecarga de operadores. (int) Y). Na versão anterior da classe Ponto. Aqui. podemos escrever instruções como: cout << “Bom Dia!” cin >> n. Desta forma. As classes stream redefiniram os operadores << e >> para operar sobre todos os tipos básicos existentes em C++. A função operator Ponto() const converterá um objeto da classe PFloat para um objeto da classe Ponto. que o objeto cout pertence à classe ostream e o objeto cin à classe istream. 2) Criando um construtor na classe Ponto. em seguida. char. Sobrecarregue os operadores aritméticos e relacionais para esta classe. menos binário (-). } Na sobrecarga deste operador.. O seu protótipo é o seguinte: void operator ()(int n. . 15. float.3 Crie uma classe para representar strings.. que a soma de duas cores é uma cor misturada com metade de cada uma das cores anteriores. Definida esta sobrecarga. para ler e escrever dados desta classe. 4. Onde Pf é um objeto da classe PFloat mas não sobrecarregamos o operador << para receber como segundo parâmetro um objeto da classe PFloat. 15.2 Crie uma classe que defina um número complexo (x + yi. para que os objetos das duas classes sejam equivalentes. Escreva um programa de teste. Neste caso. que imprime na tela uma string de caracteres e. podemos então passar um objeto da classe Ponto para um objeto cout. char ch). módulo (%). 15. como fazemos com qualquer tipo básico. Reimplemente os operadores aritméticos. os dados de um objeto Ponto: cout << "\n p1 = " << P1. o programa utiliza a função de conversão de objeto PFloat em objetos do tipo Ponto definida acima. Entretanto. Este exemplo. Defina as outras funções aritméticas.5 Crie uma classe para representar as cores (class Cor). o que acontece na linha de código abaixo: cout << "\n pf = " << Pf. Utilize o princípio. divisão (/). para converter este objeto e utilizar a função operadora << definida para objetos do tipo Ponto. onde x e y são do tipo float e i é a raiz quadrada de –1). de atribuição e lógicos para o contexto desta classe. todos os operadores aritméticos. as operações aritméticas de atribuição e as operações lógicas. O mesmo princípio pode ser utilizado para a sobrecarga do operador >> associando um objeto da classe istream (cin) a um objeto da classe Ponto.'<< aP. mostra a importância e flexibilidade das conversões de tipos.6 Exercícios 15. Defina. Podemos verificar o emprego desta função sobrecarregada através da instrução abaixo.) para objetos desta classe. para a leitura/escrita de objetos desta classe. de bits e lógicos para esta classe.4 Inclua uma sobrecarga do operador de chamada à função () na classe string anterior. Crie uma outra classe para a representação de números complexos no plano polar. Crie funções de conversão. multiplicação (*).15.Y <<')'. definimos como o objeto da classe Ponto será apresentado na tela. Sobrecarregue os operadores << e >> da classe stream. Esta sobrecarga atribui o caracter ch ao enésimo caracter da cadeia. 15.Informática Industrial I DAS/UFSC OS << '(' << aP. Sobrecarrrege o operador [] para controlar o acesso a elementos individuais da classe string e crie uma função que converta objetos da classe string em um ponteiro do tipo char. Utilize os operadores para os objetos cout e cin. Marcelo Ricardo Stemmer 146 .1 Acrescente a classe Ponto a sobrecarga dos operadores: menos unário (-). Crie funções conversoras dos tipos básicos (int.X << '.uma dúvida surge. podemos definir como objetos do modelo o cliente que chega na agência e os funcionários do banco. mantendose o princípio de que cada subclasse herda as características da classe da qual foi derivada.Informática Industrial I DAS/UFSC 4.Modelagem aplicando-se o princípio da Herança. Ao modelarmos estas duas entidades. o conceito de subclasse ou classes derivadas é chamado de herança. dizemos que as classes funcionários e clientes herdam da classebase pessoa todas as características que definem um ser humano no nosso modelo. Em programação orientada a objetos. Por exemplo. Então.16 Herança Nos capítulos anteriores definimos que classe representa um tipo de objeto. Classe Funcionário C D E Classe Cliente F Pessoa A B G Pessoa A B Classe-Base Pessoa A B Herança Funcionário C D E Cliente F G Classes Derivadas Figura 27 . Por serem pessoas. Além das características herdadas. basta definir que a classe acionista será Marcelo Ricardo Stemmer 147 . Em C++. quando estamos modelando o funcionamento de um banco. Em C++. Para não representar duas vezes o elemento pessoa. criamos então uma entidade separada chamada pessoa e descrevemos através desta a entidade pessoa. ambas as entidades conterão necessariamente a descrição de uma pessoa mas os seus dados específicos. Na Figura 27 apresentamos a diferença entre as duas modelagens. Com o princípio da herança. cada subclasse tem suas características particulares. Entretanto. o nosso modelo ainda ganha em flexibilidade e em organização do projeto. a classe de origem é chamada classe-base e as classes que compartilham as características de uma classe-base e têm outras características adicionais são chamadas de classes derivadas. quando modelamos um ambiente através da orientação a objetos. considerando que todo acionista também é um ser humano. O processo de hierarquia está presente quando dividimos classes em sub-classes. além de precisarmos modelar somente uma vez a entidade pessoa. existem alguns tipos (classes) de objetos que possuem características semelhantes com outros tipos (classes) de objetos. Suponha que neste modelo você tenha que futuramente incluir a entidade “acionista” no modelo do banco. uma na entidade cliente e outra na entidade funcionário. Bom. definimos uma classe-base quando identificamos características comuns em um grupo de classes. ambas entidades são seres humanos. percebemos que ambas possuem determinadas características em comum. Após a definição desta nova entidade. criamos uma classe para cada tipo de objeto presente e modelado no ambiente. h> #include <string. apresentaremos na forma de um exemplo a sintaxe empregada em C++. podemos utilizar a nossa classe-base pessoa para definir estas três novas classes. O bom entendimento da metodologia orientada a objetos. e adicionar a classe acionista as suas propriedades particulares.16. derivada da classe Pessoa.. precisamos fazêlo da forma mais genérica possível. somente precisamos adicionar as propriedades particulares da classe cliente-universitário como: o número de matrícula. A orientação a objetos é realmente muito poderosa. funcionário e cliente-universitário. #include <iostream. você terá grandes vantagens em termos de reutilização e baixo custo de projeto. // Exemplo de classes derivadas . Modelar um sistema significa representar todas as propriedades importantes deste e não descrever este da maneira mais detalhada possível. é possível adicionar a ela características diferentes que a tornarão capaz de representar exatamente o que desejamos. diminuirá a velocidade do programa e aumentará o tamanho deste. Tenha consciência ao modelar um sistema e bom-senso para definir as classes e as suas relações. Como exemplo. assim. o nome do curso e a data prevista para a formatura. ganhando assim em tempo de projeto. precisamos modelar pessoas com diferentes propriedades: engenheiros. criando diferentes classes para modelar diferentes tipos de clientes. O processo de herança vai além da derivação simples.O uso de uma biblioteca de classes oferece uma grande vantagem sobre o uso de uma biblioteca de funções: o programador pode criar classes derivadas de classes-base da biblioteca. Outro aspecto importante é a reutilização do programa. a eficiência do seu programa orientado a objetos depende diretamente da qualidade do seu modelo. permitindo-nos a construção de projetos flexíveis. A facilidade com que classes existentes podem ser reutilizadas sem ser alteradas é um dos maiores benefícios oferecidos por linguagens orientadas a objetos. representamos esta entidade como uma classe derivada da classe cliente. cheios de erros. Modelos enxutos e bem definidos. seja este real ou abstrato. Modelos enormes e obscuros.Informática Industrial I DAS/UFSC derivada da classe-base pessoa. Podemos ainda refinar o modelo acima. Aqui. Esta classe seria um refinamento da classe cliente e. Você pode então criar uma biblioteca com todas as classes definidas que poderão vir a ser o núcleo de muitos programas. geram programas “gordos” e complexos.1 Derivando uma Classe Agora mostraremos como podemos implementar em C++ a criação de uma classe base e a sua derivação criando uma nova classe. Neste caso. herdando todas as suas propriedades (métodos e atributos). Isto diminuirá a flexibilidade do seu modelo. consideravelmente o tempo deste projeto. Uma classe derivada pode herdar características de mais de uma classe-base. ser a classe-base de outra classe. aumentará a quantidade de erros. Desta forma. aumentará o tempo de projeto. Não exagere no nível de detalhe do seu modelo. Podemos criar uma classe para modelar os clientes que são universitários. sem alterar a classe-base.. Suponha que amanhã apareça um projeto para modelarmos uma célula de produção de uma fábrica. permitindo a reutilização de partes do modelo e do código bem como a fácil expansão do sistema. por isso. geram programas velozes e flexíveis. Neste modelo. poderemos então aproveitar diversas entidades do nosso modelo como as classes pessoa. por sua vez. Diminuindo. Quando mais genérico for o modelo. Entretanto. mais flexível será o nosso sistema e maior será a reusabilidade e expansibilidade do nosso sistema. vamos modelar a classe Pessoa apresentada como exemplo acima e a classe cliente. Isto significa que. cliente. permitirá que você modele adequadamente um sistema qualquer. Uma classe que é derivada de uma classe-base pode. ilegíveis e que não podem ser reaproveitados. Classes derivadas não estão limitadas a herança única. 4. Neste sentido. Se recebermos um outro novo projeto para representar uma padaria. gerentes e funcionários.h> Marcelo Ricardo Stemmer 148 . Sempre que estivermos modelando um ambiente. RG. public: Pessoa(). strcpy( Nome. RG = aRG. aNome).Informática Industrial I DAS/UFSC #define Nome_Size 80 class Pessoa { protected: char * int long int Nome.GetNome()).getline( (char *)Nome. RG = 0. Idade. Pessoa(char * aNome. cin. ~Pessoa(). Marcelo Ricardo Stemmer 149 } . int aId = 0. Idade = aP. Nome = 0. aP. strcpy( Nome. void GetData(). cout << "RG : ". Pessoa(Pessoa const & aP). } int GetIdade() const { return Idade. Idade = aId. } Pessoa::Pessoa( char * aNome. cout << "Idade : ". } long int GetRG() const { return RG. Idade = 0. Nome_Size). RG = aP. int aId. } } void Pessoa::GetData() { cout << "\nNome : ". Pessoa::Pessoa() { Nome = new char[Nome_Size]. } Pessoa::~Pessoa() { if(Nome != 0) { delete Nome. } Pessoa::Pessoa(Pessoa const & aP) { Nome = new char[Nome_Size]. }.GetIdade(). cin >> Idade. long int aRG) { Nome = new char[Nome_Size]. char const * GetNome() const { return Nome.GetRG(). long int aRG = 0). OS << "\n Conta : " << C. Cliente & const C) { OS << Pessoa(C). } ostream & operator <<(ostream & OS.GetSaldo(). Cliente(char * aNome. int aConta. Cliente::Cliente() : Pessoa() { Conta = 0. int aConta = 0. long int aRG = 0.GetConta() << "\n Saldo : " << C. int aSaldo) : Pessoa(aNome. Pessoa & const P) { OS << "\n\n Dados Pessoais ---------------" << "\n Nome : " << P. int GetConta() const { return Conta.GetIdade() << "\n RG : " << P. aId. } void Cliente::GetData() { Pessoa::GetData(). ostream & operator <<(ostream & OS.Informática Industrial I DAS/UFSC cin } >> RG. aRG) { Conta = aConta. int aId = 0. Saldo = aSaldo. long int aRG. int aId. Saldo = 0. public: Cliente(). }. cin >> Saldo. } void GetData().GetNome() << "\n Idade : " << P. } int GetSaldo() const { return Saldo. int Saldo.GetRG(). } class Cliente : public Pessoa { protected: int Conta. } void main() { Pessoa P1("Carlos". Marcelo Ricardo Stemmer 150 . 1315678). } Cliente::Cliente(char * aNome. return OS. cout << "Conta : ". 18. int aSaldo = 0). cin >> Conta. cout << "Saldo : ". return OS. Entretanto. Observe que membros protected não podem ser acessados por nenhum objeto declarado fora dessas classes.16. } Marcelo Ricardo Stemmer 151 .Pessoa::GetData().3 Construtores & Destrutores Se nenhum construtor for especificado na classe derivada. 4. Pessoa P3 = C1. cout << C1 << C2. Membros protected são semelhantes a membros private. Nem sempre queremos criar objetos da classe-base.16. Por isso. C2. int aSaldo) : Pessoa(aNome. cout << P1 << P2 << P3. criou-se os membros protected. declare como protected os membros privados necessários às classes derivadas. Pessoa P2 = P1. } Para derivar uma nova classe de uma classe já existente. exceto pelo fato de que são visíveis a todos os membros de uma classe derivada. basta indicar o nome da classe-base após o nome da nova classe. A classe Cliente incorpora todos os membros da classe Pessoa. 4. 123432). 17. 1234.Informática Industrial I DAS/UFSC Cliente C1. os dados definidos na classe-base Pessoa estarão disponíveis a funções membro da classe Cliente pois foram definidas como protected. Entretanto. Sempre que você escrever uma classe que pode vir a ser uma classe-base de outras classes. Observe os construtores da classe Cliente: Cliente::Cliente() : Pessoa() { Conta = 0. o construtor da classe-base será usado automaticamente. nenhum membro privado da classe-base pode ser acessado pela classe derivada. Saldo = aSaldo. Muitas vezes declaramos classes somente para que estas sirvam como uma classe-base para um conjunto de classes derivadas. terão restrições do tipo private para acessos fora da classe-base ou fora da classe derivada. long int aRG. Entretanto. o que indica que nenhuma instância (objeto) delas é criado. C1. o termo abstrato tem uma definição mais precisa quando usado com funções virtuais. apresentado no próximo capítulo. aRG) { Conta = aConta. Qualquer membro público da classe-base é automaticamente um membro da classe derivada. class Cliente : public Pessoa Esta declaração indica que a classe Cliente é derivada da classe Pessoa. int aId. aId. além de seus próprios membros. separado por dois-pontos (:).2 Dados Protected Observe que a parte pública da classe-base está disponível à classe derivada e a qualquer objeto dessa classe. } Cliente::Cliente(char * aNome. O nome da classe-base pode ser precedido da palavra public ou da palavra private. int aConta. Segundo este princípio. Saldo = 0.GetData(). Classes usadas somente para derivar outras classes são geralmente chamadas classes abstratas. C2("Pedro". GetData(). No nosso programa exemplo. Este construtor aloca um espaço de memória para armazenar os seus dados e depois copia os valores contidos do objeto passado como argumento. por sua vez. 4. o compilador copia. geralmente utilizado na conversão de outros objetos para este tipo ou na atribuição de objetos. que antes de liberarmos a memória vamos testar se o ponteiro atual é válido.Nome apontarão para a mesma localização na memória. definimos um destrutor para a classe para liberar a memória alocada antes de destruir o objeto. ao membro Nome de P2 será atribuído o conteúdo do membro Nome de P1. implementamos o construtor de cópia para os objetos da classe Pessoa: Pessoa(Pessoa const & aP). mas sim o valor apontado por este ponteiro. Desta forma.16. e a chamada ao construtor com argumentos da classe Cliente. Isto causa a chamada ao construtor sem argumentos da classe Pessoa. Para evitar que este erro aconteça. 123432). Note. Entretanto. qualquer modificação na cadeia de caracteres de um dos objetos afetará diretamente o outro. P2. enviando os argumentos recebidos para o construtor da classe-base Pessoa que. liberando assim a memória alocada. um erro fatal será gerado. Este construtor chama o construtor correspondente da classe-base. destruindo portanto a mesma memória apontada por P2. o compilador irá utilizar o destrutor da classe-base.Informática Industrial I DAS/UFSC Estes construtores têm uma sintaxe não familiar: os dois-pontos seguidos do nome da função construtora da classe-base.Nome e P1. como resultado. Note que esta função não copia o endereço contido em Nome. Marcelo Ricardo Stemmer 152 . o membro Nome é um ponteiro e.16. 4. byte a byte. todo o conteúdo de memória de um objeto no outro. destruirá a memória alocada e apontada por P1. incluímos a seguinte instrução nos construtores da classe: Nome = new char[Nome_Size]. Mas a classe Cliente não define nenhum destrutor. Reimplemente este operador sempre que a sua classe contiver ponteiros com alocação dinâmica como atributos. Em outras palavras. Evitando assim o problema descrito acima. Isto implica que quando destruirmos um objeto da classe Cliente. O seguinte problema acontecerá: quando você atribui um objeto a outro. 17. quando fornecemos valores para a inicialização do objeto.4 Construtor de Cópia & Alocação Dinâmica O programa cria o objeto P2 e então atribui a ele o conteúdo do objeto P1.5 Chamadas a Funções O objeto C1 da classe Cliente usa a função GetData() membro da classe Cliente. Este construtor de cópia é muito importante. a classe Pessoa tem um atributo do tipo ponteiro que é alocado dinamicamente quando criamos um objeto e é destruído (liberado) quando destruímos este objeto. usa o construtor com argumentos da classe Cliente. inicializa o objeto. Para tal. Quando o destrutor de P1 é chamado. Observe. Um problema mais sério ocorre quando os objetos envolvidos têm escopos diferentes. na instrução: C1. A instrução: Cliente C2("Pedro". Se P2 tentar acessar o conteúdo deste ponteiro. que o construtor da classe derivada chama o construtor da classe-base e depois executa algumas rotinas para inicializar somente os dados específicos da classe-derivada. Então. 1234. quando um objeto é criado sem valores de inicialização. com mesmo nome de uma função da classe-base.Informática Industrial I DAS/UFSC O compilador sempre procurará primeiro pela função na classe que define o objeto (no caso.6 Herança Pública e Privada Declaramos a classe derivada Cliente especificando a palavra public: class Cliente : public Pessoa A declaração public indica que os membros públicos da classe-base serão membros públicos da classe derivada e os membros protected da classe base serão também membros protected da classe derivada.GetData(). Por exemplo.16. Os membros públicos da classe-base podem ser acessados por um objeto da classe derivada. usará sempre funções da própria classe-base pois não conhece nada sobre a classe derivada. imagine que você tenha uma função da classe-base que trabalha Marcelo Ricardo Stemmer 153 . Os membros privados da classe-base serão sempre inacessíveis fora da classe-base. C1. a função da classe derivada será executada se for chamada por meio de um objeto da classe derivada.Se um objeto da classe base é criado. Esta instrução executa a função GetData() da classe-base dentro da definição desta função na classe-derivada. 4. Mas há momentos em que a derivação privada é desejável. Se ele encontrar em uma classe-base. possa acessar a que está na classe-base. mas não aos seus objetos. então qual das versões da função será utilizada pelo compilador? A regra é a seguinte: Se duas funções de mesmo nome existem uma na classe-base e outra na classe derivada. C2. Podemos criar funções-membro de uma classe derivada que tenham o mesmo nome de funções-membro da classe-base. A diferença das instruções acima é que para o primeiro objeto. estaremos utilizando a versão da função GetData() definida na classe derivada e para o segundo objeto estaremos utilizando a versão da função definida na classe-base. A distinção entre as duas chamadas é feita pelo operador de resolução de escopo (::). Isto faz com que a sintaxe da chamada a elas. Estes membros são acessíveis aos membros da classe derivada. independentemente de tratar-se de um objeto da classe-base ou da classe derivada. O operador de resolução de escopo permite que se especifique exatamente qual é a classe da função que queremos executar.Pessoa::GetData(). o compilador executará a função GetData() da classe-derivada e o resultado será uma seqüência infinita de chamadas recursivas. Para que uma função da classe derivada. o compilador executará a função encontrada. A declaração private pode ser usada no lugar de public e indica que tanto os membros públicos quanto os protegidos da classe-base serão membros privados da classe derivada. Sem o uso do operador de resolução de escopo. por meio de um objeto. Geralmente. Cliente). a derivação privada é raramente usada. Nenhuma classe derivada pode acessar um membro privado de uma classe base. um objeto da classe derivada não terá acesso a nenhum membro da classe-base. Se o compilador não encontrar esta função então ele irá procurar na classe-base da classe do objeto. Portanto. é necessário o uso do operador de resolução de escopo (::): Pessoa::GetData(). senão ocorrerá um erro. A função GetData() está definida com o mesmo protótipo tanto na classe-derivada quanto na classe-base. seja a mesma. K pode ser derivada de Z. Sobrecarregamos os operadores << associados a objetos da classe ostream. por sua vez é também uma classe derivada.16. que utilizamos uma conversão na instrução abaixo: OS << Pessoa(C).7 Conversões de Tipos entre Classe-Base e Derivada Visto que Cliente é um tipo de Pessoa. Este construtor é utilizado para converter o objeto da classe derivada em um objeto da classe base sem que ambos objetos contenham o mesmo endereço no ponteiro e venham a causar um erro de acesso à memória. que .16. A construção de hierarquias de herança múltipla envolve mais complexidade do que as hierarquias de herança simples. Aqui. Esta complexidade diz respeito ao desenho da construção das classes e não a sintaxe de uso. Esta conversão converte temporariamente o objeto C da classe Cliente para um objeto da classe Pessoa. para um objeto da classe base antes de chamarmos a função. Este processo é chamado de herança múltipla.8 Níveis de Herança Uma classe por ser derivada de outra classe . Por exemplo: Pessoa P3 = C1. class X {}. Aqui não utilizamos o operador. class Z : public Y {}. Este processo pode ser estendido para qualquer número de níveis.9 Herança Múltipla Uma classe pode herdar as características de mais de uma classe. Perceba que na implementação da sobrecarga do operador << para o objeto da classe ostream e um objeto da classe Cliente. 4. faz sentido pensar em converter um objeto da classe Cliente num objeto da classe Pessoa. Isto causará a chamada do operador << definido para a classe Pessoa. class Y : public X {}.Informática Industrial I DAS/UFSC perfeitamente com objetos da classe base.16. Y é derivada de X. 4. // C1 é um objeto da classe Cliente Todos os membros da classe-base P3 recebem os valores dos membros correspondentes do objeto C1 da classe derivada. C++ permite a conversão implícita de um objeto da classe derivada num objeto da classe-base. e assim por diante. imprimindo na tela os dados da classe Pessoa presentes no objeto da classe Cliente. A sintaxe de múltiplas heranças é similar à de uma única herança. Esta instrução opera como se estivéssemos chamando uma função da classe-base utilizando o operador de resolução de escopo. para facilitar a apresentação dos dados dos objetos de ambas as classes na tela. 4. Neste exemplo. não podemos atribuir um objeto da classe-base a um objeto da classe derivada. mas gera resultados errados quando usado com objetos da classe derivada. e Z é derivada de Y. A derivação privada neste caso é uma solução bem elegante. mas convertemos o objeto da classe derivada. O que tem o mesmo resultado. Entretanto a atribuição inversa não é válida. Eis um exemplo que representa os imóveis a venda de uma imobiliária : // Heranca Multipla Marcelo Ricardo Stemmer 154 . o construtor de cópia da classe Pessoa evitará que um erro ocorra devido a ponteiro presente na classe. cout << "\tArea Total: ". 30). quartos = 0. cin. AreaTotal. fone[20]. strcpy(fone. } }. public: Imovel() { end[0] = bairro[0] = '\0'. public: Cadastro() { nome[0] = fone[0] = '\0'. } Cadastro(char n[]. bairro[20]. AreaUtil = au.getline(bairro. n). int quartos. } Imovel(char e[].b).getline(end. Marcelo Ricardo Stemmer 155 . } void GetData() { cout << "\n\tNome: ". 20). cout << "\n\tFone: " << fone. cin >> AreaTotal. float at. f).h> <string. cout << "\tFone: ". AreaUtil = AreaTotal = 0. char b[].getline(fone. float AreaUtil.h> class Cadastro { private: char nome[30]. 30).Informática Industrial I DAS/UFSC #include #include #include #include <iostream.h> <iomanip. float au. cout << "\tBairro: ". cin. quartos = q. char f[]) { strcpy(nome. cout << "\tArea Util: ". cin.h> <stdio. } void GetData() { cout << "\n\tEnd: ". class Imovel { private: char end[30]. AreaTotal = at. int q) { strcpy(end. } void PutData() { cout << "\n\tNome: " << nome.getline(nome. 20). cin >> AreaUtil. e). strcpy(bairro. cin. } void GetData() { cout << "\n\tTipo : ". char f[]. Imovel().} Venda(char n[].Informática Industrial I DAS/UFSC cout << "\tNo. Loja.Imovel: ". cin >> valor.f). cout << "\tValor R$ : ". Tipo::GetData(). class Tipo { private: char tipo[20]. 20). class Venda : private Cadastro.au.. t).. Imovel(e... } void PutData() { cout << "\n\tEnd : " << end. Galpao public: Tipo() { tipo[0] = '\0'. float au.... // Residencial. Tipo(t) { valor = v. } void GetData() { cout << "\n . cout << "\n . char e[].b. float at. public Tipo { private: float valor. cout << "\n . cout << "\n\tArea Util : " << setiosflags(ios::fixed) << setprecision(2) << AreaUtil << "\n\tArea Total : " << AreaTotal << "\n\tQuartos : " << quartos. int q. cout << "\n\tBairro : " << bairro. char t[]. public Imovel. public: Venda() : Cadastro().. Tipo() {valor = 0. Cadastro::PutData(). float v) : Cadastro(n. Quartos: ".Imovel: ".q). } void PutData() { cout << "\n .getline(tipo. cin >> quartos. Cadastro::GetData(). Imovel::PutData(). } }. } void PutData() { cout << "\n\tTipo: " << tipo. cin. char b[].Proprietario: ". Imovel::GetData().at. } }. } Tipo(char t[]) { strcpy(tipo. Marcelo Ricardo Stemmer 156 .Proprietarios: ". Muitas vezes podemos substituir uma herança por um objeto da classe-base. Imovel().Imovel::PutData(). O mais comum é quando duas classes-base têm. Quando a função é acessada por meio de um objeto da classe derivada. char t[].at.} Venda(char n[]. Marcelo Ricardo Stemmer 157 . float v) : Cadastro(n. Por exemplo. o compilador não reconhecerá qual das duas estará sendo chamada. Cadastro::PutData(). Cadastro tem derivação do tipo privado enquanto as demais classes têm derivações do tipo público.Informática Industrial I DAS/UFSC Tipo::PutData(). C. Tipo(t) { valor = v.GetData(). enquanto a classe derivada destas duas não tem nenhuma função com este nome. }. float au.0. float at. Tipo() {valor = 0. Ao chamar os construtores das classes base. } }. Uma boa modelagem pode definir claramente quais serão as classes criadas e como elas deverão interagir. Tipo::PutData(). uma função de mesmo nome (protótipo). Alguns tipos de problemas podem aparecer em certas situações envolvendo herança múltipla. C. "Rua Rocha. int q. devemos lembrar que os nomes dos construtores são colocados após os dois-pontos e separados por vírgulas. cout << "\n\n Digite um Imovel para Vender!\n". char b[]. A ordem de chamada é a mesma da ordem em que eles aparecem escritos. notificamos o compilador que a classe Venda é derivada das classes Cadastro. A escolha do método que devemos aplicar depende muito do modelo adotado e do desempenho esperado. 50.f).q). V. As funções GetData() e PutData() da classe Venda incorporam a chamada às funções correspondentes das classes Cadastro. Imovel e Tipo.. void main() { Venda C.PutData(). char e[]. Os construtores da classe Venda são os seguintes: Venda() : Cadastro(). 33". Parâmetros podem ser passados assim como em qualquer outro construtor.0 ). Imovel(e. Tipo::GetData(). } Note que a definição de um construtor de uma classe com herança múltipla é muito similar com o construtor de uma classe com herança simples. } Através da declaração: class Venda : private Cadastro..PutData(). "3203322". podemos chamar a função PutData() da classe Imovel com um objeto da classe Venda através da instrução: C. cada uma delas. Para informar ao compilador qual das duas funções está sendo solicitada. Imovel::GetData(). "Comercial". 75.b.au. char f[]. cout << "\n\tValor R$ : " << valor. 80000. "Coqueiros". devemos utilizar o operador de resolução de escopo (::). Imovel::PutData(). public Imovel.V("Eduardo Mattos". public Tipo { .0. Imovel e Tipo empregando o operador de resolução de escopo (::) para efetuar a chamada das funções das classes base: Cadastro::GetData(). cout << "\n\n* Imovel Para Venda : ". 2. soldar em cima desta uma caixa. indique onde este deve estacionar.17 Funções Virtuais e Amigas Neste capítulo discutiremos tópicos avançados sobre classes. 16. Cidade. cliente-universitários. Temos os clientes normais (classe-base) e clientes universitários ou especiais. onde temos uma classe base e duas classes derivadas. crie a classe Motor que contém NumCilindro e Potencia.3 Imagine que você deva escrever um programa para armazenar veículos. Aceite as propriedades propostas como sugestões mas crie o seu próprio programa. Suponha o seguinte exemplo. velocidade máxima e preço. Termine o programa que modelas as pessoas que compõem o ambiente banco : acionista. 4. Inclua a carga máxima. motor de passo e motor assíncrono. Verifique se um veiculo pode ou não estacionar antes de permitir a entrada. As nossas classes definem os tipos de clientes em um banco. Crie a classe CarroPasseio usando as classes Motor e Veiculo como base. A mesa esta a 50 cm na frente do robô e a caixa está a 50 cm a direita do robô. Primeiramente. Inclua um construtor com argumentos com valores default que inicialize os dado com zeros e um construtor de cópia. altura máxima e comprimento. Crie a classe caminhao derivada das classes Motor eVeiculo. Crie um robô que seja capaz de pintar a parte superior de uma mesa. 4. 4. o preço médio de um prato.1 No início começamos discutindo a modelagem de um banco orientado a objetos. 16. 16. Crie um programa para o controle de um estacionamento que tenha uma área fixa e controle o acesso de veículos no estacionamento.2 Crie uma classe Empresa capaz de armazenar os dados de uma empresa (Nome. Cada elo pode ser uma barra reta ou uma curva suave de 90 graus. transversal (geram um deslocamento linear do elo) ou juntas que não geram movimento nenhum. Use a classe Empresa como base para criar a classe Restaurante. quando derivamos um grupo de classes a partir de uma classe-base. Se puder. Cobriremos a definição e o uso de funções virtuais e funções amigas.10 Exercícios 16. Reflita sobre o problema. CEP. certas funções-membro precisam ser redefinidas em cada uma das classes derivadas. cliente. simplesmente ligam dois elos. Fone e E-mail). Inclua cor e modelo. End. Um robô pode ter uma garra para pegar objetos. Modele um robô segundo as considerações acima. Escreva a classe Veiculo contendo peso. este seria o único método de acesso a esta função sem causar um erro de ambigüidade. uma garra para fazer operações de soldagem e uma garra para fazer operações de pintura. etc. Sobrecarrega o operador ostream <<. funcionário. Inclua o tipo de comida. pessoa-física. crie um modelo e decida quais propriedades dos veículos devem ser descritas.4 Um robô pode ser composto por três tipos de motores : motor de corrente contínua. pessoa-jurídica.1 Funções Virtuais Muitas vezes. funções para adquirir os seus dados e para imprimí-los na tela. Estado. CGC. definindo a geometria do robô e como será o movimento deste.16. Marcelo Ricardo Stemmer 158 . Um robô pode conter juntas com movimento angular (geram uma variação no ângulo entre dois elos).Informática Industrial I DAS/UFSC Caso a classe derivada não contivesse esta função.17. A função print() está definida na classe base e redefinida nas classes derivadas. Um dos meios é criar uma matriz de ponteiros para os diferentes objetos envolvidos. duas condições tiveram que ser introduzidas. Segundo este princípio. Universitario D1. Observe que desejamos que funções completamente diferentes sejam executadas com por meio da mesma instrução de chamada. // matriz de ponteiros da classe-base Cliente B. o compilador trata todos os endereços da lista de ponteiros como endereços da classe-base. Em C++ indica a habilidade de uma única instrução chamar diferentes funções e portanto assumir diferentes formas. considera que Marcelo Ricardo Stemmer 159 . Se o ponteiro p[i] apontar para um cliente normal. A característica de chamar funções membros de um objeto sem especificar o tipo exato do objeto é conhecida como polimorfismo. Um ponteiro para um objeto de uma classe derivada é de tipo compatível com um ponteiro para um objeto da classe-base. } Planejamos agrupar um conjunto de objetos destas classes em uma lista única. através da chamada da função print() : for(int i = 0. todas as diferentes classes de clientes devem ser derivadas da mesma classe-base. A palavra polimorfismo significa “assumir várias formas”. p[1] = &D1. } }. class Universitario : public Cliente { public: void print() { cout << "\nCliente Universitario".Informática Industrial I DAS/UFSC // Testando funcoes Virtuais #include <iostream. se p[i] apontar para um cliente especial. Para que o exemplo anterior funcionasse corretamente. Em primeiro lugar. i<10. a função da classe de clientes especiais deverá ser executada. criamos um vetor de ponteiros da classe base e atribuímos a ele endereços das classes derivadas.} }. Podemos imprimir os dados da lista. } }. ou seja. o nosso objetivo é ter uma lista única de clientes e diferenciá-los pelos tipos de objetos que os definem. p[0]->print(). a função print() deve ser declarada como virtual na classe-base. Isto é. void main() { Cliente * p[3]. p[2] = &D2. Qual seria o tipo da matriz tendo em vista que ela deve armazenar ponteiros para objetos de classes diferentes? A resposta está em como o compilador opera ponteiros em situações deste tipo. Apesar de termos fornecidos os endereços de objetos de classes derivadas. Especial D2.h> class Cliente { public: virtual void print() { cout << "\nCliente". class Especial : public Cliente { public: void print() { cout << "\nCliente Especial". como você pode observar acima. p[0] = &B. p[2]->print(). p[1]->print(). Em segundo lugar. a função da classe base deverá ser executada. i++) p[i]->print(). A solução é declarar o destrutor da classe-base virtual. mesmo que não compartilhem o mesmo nome do destrutor Marcelo Ricardo Stemmer 160 . A função serve somente para prover uma interface polimórfica para as classes derivadas. Esta ordem não é mantida quando um ponteiro para a classe-base contém um objeto de uma classe derivada. Uma classe que não pode ser utilizada para criar objetos é dita classe abstrata e existe somente para ser usada como base para outras classes. Então. p[i]->print(). A sintaxe (=0) é usada somente para indicar ao compilador que esta é uma função virtual pura. e não tem corpo.Informática Industrial I DAS/UFSC os ponteiros apontam para objetos da classe base. entretanto aumenta a flexibilidade no projeto do software e permite criar bibliotecas de classes que outros programadores podem estender não tendo o arquivo-fonte. o compilador chama somente o destrutor da classe-base. mesmo que o ponteiro aponte para um objeto da classe derivada. A classe que define uma função virtual pura é uma classe abstrata pois não se pode declarar nenhum objeto dela. o compilador não conhece qual classe p[i] contém antes de o programa ser executado. eles são executados na ordem reversa à qual o construtor é executado. interpreta a ação e vincula a ação à função apropriada. As instruções de chamada a funções não-virtuais são resolvidas em tempo de compilação e são traduzidas em chamadas a funções de endereços fixo. quando é possível identificar qual o tipo de objeto é apontado por p[i].17.O programador especifica que uma determinada ação deve ser tomada em um objeto por meio de uma instrução. Quando uma instrução de chamada a uma função virtual é encontrada pelo compilador. Uma função virtual pura é uma função virtual sem bloco de código ou o bloco de código não contém nenhuma instrução. Se o operador delete é aplicado a um ponteiro da classe-base. A resolução dinâmica envolve mais memória e tempo de execução. O propósito de uso de uma função virtual pura é me situações em que a função nunca será executada e está presente somente para que seja redefinida em todas as classes derivadas. na hora da execução. Toda classe que contém pelo menos uma função virtual pura ou uma classe derivada que não redefine a função virtual pura de sua classe-base é abstrata. ele não tem como identificar qual é a função associada em tempo de compilação. Para acessar objetos de diferentes classes usando a mesma instrução. um ponteiro para uma classe abstrata pode ser declarado para manipular objetos de classes derivadas. a instrução é avaliada em tempo de execução. Isto faz com que os destrutores de todas as classes derivadas sejam virtuais. O programa. O compilador ignora o conteúdo do ponteiro p[i] e usa o seu tipo para identificar a funçãomembro a ser chamada. 4.2 Destrutores Virtuais Se destrutores são definidos na classe-base e na classe derivada. Entretanto. A função print() pode ser definida como virtual pura da seguinte forma: virtual void print() =0. o destrutor da classe derivada é chamado e em seguida o destrutor da classe-base é chamado. p[i]->Cliente::print(). Isto faz com que a instrução seja vinculada a função antes da execução. Quando um objeto da classe derivada é destruído. Em instruções como a escrita acima. A resolução dinâmica permite que uma instrução seja associada a uma função no momento de sua execução. Quando executamos uma função utilizando este ponteiro. devemos declarar as funções da classe-base que serão reescritas em classes derivadas usando a palavra-chave virtual. Isto é chamado de resolução dinâmica. O sinal de igual (=) e o valor 0 não têm nenhum efeito aqui. a função será executada como se o objeto referenciado fosse da classe base. Informática Industrial I DAS/UFSC da classe-base. Então, se delete é aplicado a um ponteiro para a classe-base, os destrutores apropriados são chamados, independentemente de qual tipo de objeto é apontado pelo ponteiro. class Base { public: }; virtual ~Base(); // destrutor virtual A classe Base tem um destrutor virtual, mesmo sendo um destrutor que não faz nada. Sempre que você escrever uma classe que tem uma função virtual, ela deve ter um destrutor virtual mesmo que não necessite dele. A razão disto é que uma classe derivada pode necessitar de um destrutor. Se um destrutor virtual está definido na classe-base, você assegura que destrutores de classes derivadas são chamados na ordem necessária. Observe que, enquanto os destrutores podem ser virtuais, os construtores não devem ser. 4.17.3 Classe-Base Virtual Além de declarar funções virtuais, podemos usar a palavra virtual para declarar uma classe inteira. A necessidade de declarar uma classe virtual é quando esta foi usada como classe-base para mais de uma classe derivada e dessas classes derivadas foi derivada outra por meio de herança múltipla. Uma classe-base não pode ser usada mais de uma vez numa mesma classe derivada. Entretanto, uma classe-base pode ser indiretamente usada mais de uma vez em classes derivadas. Observe a classe Super do exemplo abaixo: #include <iostream.h> class Base { protected: int valor; public: Base(int n = 0) {valor = n;} virtual void Print() { cout << "\nValor : " << valor; } }; class Deriv1 : virtual public Base { public: Deriv1(int n = 0) : Base(n) { } }; class Deriv2 : virtual public Base { public: Deriv2(int n = 0) : Base(n) { } }; class Super : public Deriv1, public Deriv2 { public: Super(int n = 0) : Base(n) { } int RetValor() { return valor; } void Print() { cout << "\nValor do Super-Objeto : " << valor; } }; void main() { Base B(5); Deriv1 D1(10); Super S(343); B.Print(); D1.Print(); S.Print(); } Neste caso, cada objeto da classe Super poderia ter dois sub-objetos da classe Base. Se um objeto da classe Super tentasse acessar dados ou funções da classe Base, ocorreria um erro de Marcelo Ricardo Stemmer 161 Informática Industrial I DAS/UFSC ambigüidade. A declaração virtual nas classes Deriv1 e Deriv2 faz com que estas classes compartilhem uma única classe-base. A classe Super só terá um sub-objeto da classe Base e não terá mais nenhum problema de ambigüidade. Os construtores de classes-base são sempre executados antes do construtor da classe derivada. Os construtores de classes-base virtuais são chamados antes de qualquer construtor de classes-base não-virtuais. 4.17.4 Funções Amigas O conceito de isolamento interno dos itens de uma classe, onde funções não-membros não teriam o privilégio de acesso aos dados privados ou protegidos desta classe, é violado por um mecanismo oferecido por C++ que permite que funções não-membro, às quais foi dada uma permissão especial, tenham acesso à parte interna da classe. Declarando uma função como amiga, ela tem os mesmos privilégios de uma função-membro, mas não está associada a um objeto da classe. No programa abaixo apresentamos a sintaxe das funções amigas: // Uso de funcoes amigas #include <iostream.h> #include <strstrea.h> class Data; // Declara que existe esta classe class Tempo { private: long h, min, s; public: Tempo(long hh = 0, long mm = 0, long ss = 0) { h = hh; min = mm; s = ss; } friend char * PrintTime( Tempo &, Data &); }; class Data { private: int d, m, a; public: Data(int dd = 0, int mm = 0, int aa = 0) { d = dd; m = mm; a = aa; } friend char * PrintTime( Tempo &, Data &); }; char * PrintTime( Tempo & Tm, Data & Dt) // Função global e amiga { char * temp = new char[50]; memset(temp, '\0', 50); strstream sIO(temp, 50, ios::out); sIO << "\n Relogio-> \t" << Tm.h << ":" << Tm.min << ":" << Tm.s; sIO << "\n Data-> \t" << Dt.d << "/" << Dt.m << "/" << Dt.a; return temp; } void main() { Tempo Tm( 15, 56, 4); Data Dt( 9, 5, 2000); char * str = PrintTime( Tm, Dt); cout << "\n" << str; Marcelo Ricardo Stemmer 162 Informática Industrial I DAS/UFSC delete str; } Neste exemplo, queremos que a função PrintTime() tenha acesso aos dados privados da classe Tempo e Data. Desta forma, usamos a palavra-chave friend na declaração da função friend char * PrintTime( Tempo &, Data &); Esta declaração pode ser colocada em qualquer posição da classe. Não há diferença se for colocada na parte pública ou na parte privada da classe. Um objeto Tempo é passado como argumento à função PrintTime(). Este argumento é necessário pois, mesmo quando se dá a uma função amiga o privilégio de acesso aos dados privados da classe, ela não é parte daquela classe, devendo ser informada sobre qual objeto agirá. A função PrintTime() cria um objeto da classe strstream. Este objeto atua como se fosse um objeto cout, entretanto em vez de enviar os dados para a saída padrão (tela), ele armazena estes dados no buffer de caracteres fornecidos ao seu construtor. Esta é uma das formas mais fáceis para converter dados de uma classe para texto (ASCII) e armazenar estes dados em um buffer de caracteres. Note que operamos sob o objeto criado assim como operamos com o objeto cout. O mesmo princípio pode ser empregado para a leitura de dados armazenados em um buffer de caracteres, operando-se como se estivéssemos utilizando o operador cin. Funções amigas são muito empregadas quando sobrecarregamos os operadores << e >> associados aos objetos cout e cin respectivamente. Desta forma definimos o operador << para imprimir os dados da classe e o operador >> para adquirir os dados da classe. Como muitas vezes desejamos que estes operadores tenham acesso aos membros privados da classe, então devemos defini-los como funções amigas. friend ostream & operator <<(ostream & OS, Tempo const & T); friend istream & operator >>(istream & IS, Tempo & T; Todo e qualquer operador que queremos sobrecarregar como sendo uma função global (i.e., recebe um parâmetro se for unário e dois se for binário) e queremos permitir que este operador tenha acesso a membros privados e protegidos de uma dada classe, devemos definir este operador como sendo uma função amiga. No nosso programa-exemplo acima, definimos que a função PrintTime()é amiga das classes Data e Tempo. Para tal, precisamos declarar nas duas classes que esta função é amiga da classe. Quando declaramos a função na classe Tempo, estaremos declarando uma função que recebe como parâmetro um objeto da classe Data desconhecida até então pelo compilador. Para evitar que o compilador gere um erro indicando que a classe não existe, devemos declarar no início do arquivo que existe a classe Data é que esta será definida posteriormente. Fazemos isto através da instrução: class Data; 4.17.5 Classes Amigas Além de ser possível declarar funções independentes como amigas, podemos declarar uma classe toda como amiga de outra. Neste caso, as funções-membro da classe serão todas amigas da outra classe. A diferença é que estas funções-membro têm também acesso à parte privada ou protegida da sua própria classe. Para modificar o programa anterior e declarar que a classe Data é amiga da classe Tempo, basta retirarmos a declaração da função amiga PrintTime() da classe Tempo e adicionarmos a declaração: friend class Data; Marcelo Ricardo Stemmer 163 Informática Industrial I DAS/UFSC Agora, se definirmos que a função PrintTime() passa a ser uma função da classe Data, ela automaticamente passará a ser amiga da classe Tempo e terá acesso a todos os membros desta classe. Uma função ou classe amiga deve ser declarada como tal dentro da classe em que os dados serão acessados. Em outras palavras, quem escreve uma classe deve especificar quais funções ou classes irão acessar a sua parte privada ou protegida. Desta forma, um programador que não tem acesso ao código-fonte da classe não poderá criar uma função amiga para esta classe. As funções amigas devem ser declaradas pelo autor da classe. Observe que a palavra chave friend oferece acesso em uma só direção. Se a classe A é amiga da classe B, o inverso não é verdadeiro. Uma função operadora amiga deve receber no mínimo um argumento objeto. Em outras palavras, você não pode criar uma função operadora binária como operator +() que receba dois inteiros como argumentos. Esta restrição previne a redefinição de operadores internos da linguagem. Alguns operadores não podem ser definidos como funções amigas; devem ser definidos como funções-membro de classe. São eles: atribuição (=), acesso de membros de ponteiros (->), () e conversores de tipo. 4.17.6 Exercícios 17.1 Escreva as classes Animal, Vaca, Bufalo e Bezerro, sendo Vaca e Bufalo derivadas de Animal e Bezerro derivada de Vaca e de Bufalo. 17.2 Modele os elementos Veículos, Moto, Carro Esportivo, Carro de Luxo, Carro Popular, Perua, Carro Mil, Jipe, Caminhão, Onibus e Caminhonete. Utilize a idéia do exercício 16.3. Crie um programa que controle uma revenda de carros. Tenha uma lista única contendo todos os veículos a venda. Utilize o princípio de um vetor de ponteiros para a classe base e empregue exaustivamente os conceitos da derivação e de funções virtuais e amigas. Permita que o usuário insira algum veículo na lista, faça consultas, liste todos os veículos disponíveis e retire um veículo da lista. 17.3 Define uma classe String que sobrecarrega os seguintes operadores para as mais variadas funções: (+), (==), (!=), (<), (>), (<=), (>=), (<<) e (>>). 17.4 Refaça os exercícios 16.1 e 16.2 empregando o princípio das funções amigas e virtuais. 4.18 Operações com Arquivos Iostream Neste capítulo, veremos brevemente as facilidades de C++ para operações de leitura e gravação em discos. Começaremos com uma breve descrição das classes usadas para executar esta tarefa, conhecidas como classes iostream. Em C++, os objetos stream são o ponto central das classes iostream. Um objeto stream pode ser pensado como um buffer para o recebimento ou envio de bytes. Desta forma, um arquivo em disco é um objeto stream. O conceito de arquivo é ampliado no sentido de considerar arquivos não somente os que existem em discos mas também o teclado, o vídeo, a impressora e as portas de comunicação. Por exemplo, o objeto cout representa o vídeo (recebimento de bytes) e o objeto cin representa o teclado (envio de bytes). As classes iostream interagem com esses arquivos. Diferentes objetos stream são usados para representar diferentes interações com periféricos de entrada e saída. Cada stream é associado a uma classe particular, caracterizada pelas suas funções de interface e pelos seus operadores de inserção e extração. Na Figura 28 apresentamos a hierarquia das classes iostream. Por exemplo, cout é um objeto da classe ostream_withassign que é derivada da classe ostream. Similarmente, cin é um objeto da classe istream_withassign que é derivada da classe istream. Objetos de destino de bytes usam o Marcelo Ricardo Stemmer 164 Os objetos cin e cout são objetos destas classes. As classes iostream e ostream são derivadas de ios e são dedicadas a leitura e impressão. respectivamente. As classes istream_withassign e ostream_withassign são usadas para a entrada e a saída padrão. além de outras. Contém ainda a sobrecarga do operador de extração >>. esta classe herda as capacidades tanto de leitura como de impressão. Para descobrir os arquivos que definem estas classes.5. para gravação e para leitura/gravação respectivamente. Contém ainda a sobrecarga do operador de inserção <<. getline(). Desta forma. ofstream e fstream são usadas na manipulação de arquivos me disco para leitura. A classe ios é a base para todas as outras classes. write(). membro da classe ostream.Informática Industrial I DAS/UFSC operador de inserção <<. além de outras. As classes istrstream. As classes ifstream. Todo objeto istream ou ostream contém um objeto streambuf derivado. Já a classe ostream contém funções como put(). A classe iostream é derivada das classes istream e ostream por meio de herança múltipla. As classes istream e ostream trabalham em conjunto com a classe streambuf. Ela contém várias constantes e funçõesmembro para as operações de leitura e impressão a todas as outras classes. Suas funções-membro implementam operações formatadas ou não-formatadas em objetos stream. membro da classe istream. Outras classes podem ser criadas pelo usuário tendo como base istream e ostream. ostrstream e strstream são usadas na manipulação de buffers de dados: para leitura. Estas duas classes são derivadas da classe ios. para gravação e para leitura e gravação respectivamente. utilize o help do seu compilador pois a nova norma ANSI C++ definiu novos nomes para estes headers. Figura 28 . read(). A classe istream contém funções como get(). Os objetos de origem de bytes usam o operador de extração >>. Marcelo Ricardo Stemmer 165 .Hierarquia das Classes Iostream do Compilador Borland C++ 4. Pessoa::Pessoa() { Nome = new char[Nome_Size]. O exemplo tratado é a classe Pessoa definida nos capítulos anteriores. void GetData().Informática Industrial I DAS/UFSC 4.h> #include <string. Pessoa(Pessoa const & aP).h> #include <iomanip.h> #include <fstream. long int aRG) { Nome = new char[Nome_Size]. A classe em si não apresenta nada de novo. strcpy( Nome. } int GetIdade() const { return Idade. Idade = 0. long int aRG = 0). } Pessoa::Pessoa( char * aNome. } friend ostream & operator <<(ostream & OS. Idade.h> #define Nome_Size 80 class Pessoa { protected: char * int long int Nome. int aId = 0. Idade = aId.h foi adicionado por causa das classes de manipulação de arquivos. char const * GetNome() const { return Nome. int aId. } Pessoa::Pessoa(Pessoa const & aP) Marcelo Ricardo Stemmer 166 . }. } long int GetRG() const { return RG. // Exemplo da class fostream #include <iostream. utilizando-se estes operadores. RG. friend istream & operator >>(istream & IS. Pessoa & P). RG = aRG. O header fstream. ~Pessoa(). RG = 0. aNome).18. Pessoa const & P). public: Pessoa(). A sobrecarga destes operadores nos permite a escrita e a leitura automática de dados da classe. somente sobrecarregamos os operadores de inserção << e extração >> de dados definidos para objetos da classe iostream.1 Estudo de Caso Vamos apresentar a leitura e escrita de arquivos a partir de um exemplo. Pessoa(char * aNome. Veja o exemplo abaixo. getline( (char *)P. 20.Informática Industrial I DAS/UFSC { Nome = new char[Nome_Size]. strcpy( Nome.GetIdade().RG. cin >> RG. } } void Pessoa::GetData() { cout << "\nNome : ". aP.GetRG().GetIdade() << "\n" << P. return OS. Idade = aP.GetNome() << "\n" << P. // Escrevendo ofstream FOut("Teste. } Pessoa::~Pessoa() { if(Nome != 0) { delete Nome.TXT". cout << "Idade : ". cin. // Lendo ifstream FIn. Nome_Size). } void main() { Pessoa Eu("Rodrigo". cin >> Idade.2345. } ostream & operator <<(ostream & OS. FOut << Eu << "\n Um dia a casa cai! \n " << setw(12) << setprecision(3) << 12.open("Teste. 231123). ios::in) Pessoa Vc. return IS. FOut. IS >> P. Nome = 0. cout << "RG : ". Nome_Size).GetNome()). } istream & operator >>(istream & IS.GetRG().getline( (char *)Nome.Idade. Fin. Pessoa & P) { IS.TXT". ios::out). Marcelo Ricardo Stemmer 167 . RG = aP. Pessoa const & P) { OS << P. IS >> P.close().Nome. } FIn.getline( Buffer. somente após a chamada a função open() é que o arquivo estará aberto. O objeto FIn terá o valor zero se o sistema operacional enviar ao programa o sinal de fim-de-arquivo e um valor não-zero caso contrário.close(). Note que escrevemos os dados no arquivo da mesma forma que escrevemos os dados na tela com cout. Estas funções foram incorporadas nas classes iostream. FIn >> Vc. fechamos este através da função close(). while(FIn) //Enquanto nao acabar o arquivo { FIn. Esta facilidade advém do fato de cout e FOut serem ambos objetos de classes derivadas da classe ostream. Primeiro criamos um objeto Pessoa. Note que o construtor não abrirá nenhum arquivo aqui. O segundo parâmetro indica que este arquivo será aberto para a leitura. Após lermos o arquivos. cout << "\nBuffer : " << Buffer. e pode ser acessada da forma: cout. ou FOut. O segundo parâmetro indica que o arquivo será aberto para a escrita. Verifique com o help do seu compilador as funções disponíveis e verificará esta observação. Nome_Size). Por exemplo. Note que fazemos uso da função getline(). cout << "\nVoce: \n" << Vc.put(‘c’). O programa verifica o término do arquivo no laço while. que recebe um buffer como parâmetro e adquire uma linha inteira do arquivo. Neste programa definimos um objeto chamado Fout da classe ofstream. Se você não fechar o arquivo.TXT”. Para ler o arquivo.0 e se aplicam para todos os objetos streams. O controle do formato da impressão e leitura pode ser executado por meio dos manipuladores e flags da classe ios. É neste momento que os dados serão salvos no arquivo. Todas as funções definidas para a leitura e escrita em C podem ser empregadas em C++. Toda formatação e função válida para cout também pode ser aplicada a FOut. o função put() foi adicionada a classe ostream. Após a escrita dos dados. Estes mecanismos foram apresentados em 0. os dados somente serão salvos quando o objeto for destruído e o arquivo. Depois escrevemos este objeto e outros dados em um arquivo e depois prosseguimos com a leitura deste. Após termos lidos o dado da classe. Depois utilizamos a sobrecarga do operador >> para fazer a aquisição dos dados da classe Pessoa contido no referido arquivo e imprimir na tela.Informática Industrial I DAS/UFSC char Buffer[Nome_Size].0.TXT” para gravação e já abre o arquivo. prosseguimos lendo linha por linha do arquivo e escrevendo-a na tela até terminar o arquivo. devemos fechar o arquivo com a função close(). será fechado pelo destrutor do objeto.put(‘c’). Desta forma. utilizamos o mesmo operador definido para escrever os dados da classe Pessoa na tela como em um arquivo. Inicializamos este objeto com o nome do arquivo “TESTE.TXT através da função open(). A função eof() desta classe poderia ser empregada com o mesmo propósito. Esta inicialização associa o objeto Fout ao arquivo em disco “TESTE. Marcelo Ricardo Stemmer 168 . Os objetos da classe ifstream têm um valor que pode ser testado para a verificação do fimde-arquivo. então. criamos um objeto da classe ifstream de nome Fin e associamos este objeto ao arquivo Teste. } Na função main() é que aparecem as novidades. membro da classe ios. Se usada sem argumento.Informática Industrial I DAS/UFSC 4. Sem erros Encontrado o fim-de-arquivo Erro de leitura ou gravação Erro irrecuperável A função clear(int status) modifica a palavra de status.18.4 Escrevendo e Lendo em Buffers de Caracteres As classes iostream interagem com a memória pela mesma sintaxe com a qual interagem com arquivos de disco. ios::in|ios::out|ios::ate). 4. \\ Arquivo para leitura e gravaçao!!!! fio.3 Testando Erros Situações de erros na manipulação de arquivos podem ser previstas verificando-se a palavra (int) de status da classe ios.18.dat”. membro da classe fstream. todos os bits de erros são limpos. Podemos trabalhar com arquivos no modo texto ou no modo binário. Este modo é definido por bits de um byte. Os bits individuais do valor retornado podem ser testados pelo operador AND bit-a-bit (&) e os seguintes valores enumerados: Bits ios::goodbit ios::eofbit ios::failbit ios::badbit Função good() eof() fail() bad() Comentário Nenhum bit setado. Esta associação pode ser feita pelo construtor da classe ou usando a função open(). Abre em binário (default é texto). numa instrução após a criação do objeto com o construtor default. ios::in|ios::binary). A palavra de status pode ser obtida pela função rdstate(). fstream fio.2 A função Open() Quando usamos um objeto da classe ofstream ou ifstream.txt”. Do contrário. onde cada um especifica um certo aspecto de abertura do arquivo. enquanto em modo binário é representado por dois caracteres. onde criamos um objeto ostrstream para criar um buffer e Marcelo Ricardo Stemmer 169 .open(“Lista.18. é necessário associá-lo a um arquivo. Exemplos: ifstream fin(“Teste. Tanto o construtor como a função open() aceitam a inclusão de um segundo argumento indicando o modo de abertura do arquivo. assim como em C. Veja o exemplo abaixo. Podemos ler e grava de e para buffers de caracteres na memória do computador. Lembre-se que o fim de linha em modo texto é representado por um único caractere. os bits setados de acordo com os valores enumerados escolhidos e combinados pelo operador OR (|): clear(ios::eofbit | ios::failbit). A lista de modos é definida na classe ios por meio de enum open_mode: Modos ios::in ios::out ios::ate ios::app ios::trunc ios::nocreate ios::noreplace ios::binary Descrição Abre para leitura (default de ifstream) Abre para gravação (default de ofstream) Abre e posiciona no final do arquivo – leitura e gravação Grava a partir do fim do arquivo Abre e apaga todo o conteúdo do arquivo Erro de abertura se o arquivo não existir Erro de abertura se o arquivo existir. 4. irá acessar diretamente o periférico.h> void main() { ostrstream OS.str(). gera código velozes.h> #include <strstrea. OS << "\n\n Um dia voce enxergara a oportunidade que recebeu!". Basta criar um objeto do tipo fstream (ifstream. // StrStream #include <iostream. IS >> x >> y >> i. cout << x << '\t' << y << '\t' << i << '\n' << ptr. imprimimos os dados na tela. char * ptr = OS. ofstream. Depois armazenamos o ponteiro deste buffer em uma variável. um buffer. Estas classes podem ser usadas para aproveitarmos os operadores << e >> para converter qualquer tipo de dado no formato texto ASCII e armazenar em um buffer de caracteres. fstream) e passar como nome do arquivo o nome do periférico. A tabela seguinte descreve estes nomes: Nome CON AUX ou COM1 COM2 PRN ou LPT1 LPT2 LPT3 NUL Descrição Console (teclado e vídeo) Primeira porta serial Segunda porta serial Primeira porta paralela Segunda porta paralela Terceira porta paralela Periférico Inexistente Marcelo Ricardo Stemmer 170 . Depois. ou para uma porta COM ou até para um outro processo via conexões TCP/IP da internet. quando bem aproveitada.5 Imprimindo em Periféricos Imprimir dados na impressora é exatamente a mesma coisa que gravar dados num arquivo de disco. Definindo o operador << e >> para toda classe.55 << "\t" << 333. int i. definimos um modo padrão para a escrita/leitura dos dados de uma classe para um arquivo. Esta é uma ferramenta muito poderosa que não pode ser desprezada e. ou um canal de I/O qualquer. O DOS define o nome de alguns periféricos ligados ao computador. criamos um objeto istrstream para ler dados do mesmo. istrstream IS(ptr). // Cria buffer para a escrita OS << "123. O manipulador ends. OS << ends. Qualquer um deles pode ser usado em nosso programa como nomes de arquivos. 4. } Note a semelhança da metodologia. Por fim. y. adiciona o terminador ‘\0’ à cadeia de caracteres. double x. toda operação feita sob este objeto. Este buffer pode ser utilizado para transmitir estes dados para a tela do micro.Informática Industrial I DAS/UFSC adicionar dados neste buffer.18. usando neste exemplo.45 \t" << 555. Em seguida. simples e com alta flexibilidade. passando para o seu construtor o ponteiro do buffer. 1. 18. Crie outro programa que faça o contrário. Quando o programa é executado para um arquivo já criptografado. ofstream ocom1(“COM1”).2 e 14.Informática Industrial I DAS/UFSC Exemplo: ofstream oprn(“PRN”). Marcelo Ricardo Stemmer 171 . 18. 4. escreva estes dados em um buffer da memória e depois envie este buffer para ser impresso na impressora.7 Escreva um programa que criptografa um arquivo usando o operador complemento bita-bit (~).4 Escreva um programa que imprima os dados de um arquivo na tela.2 Escreva um programa para banco de dados de uma biblioteca. Utilize todos os conceitos apresentados neste capítulo.5 Escreva um programa que converta arquivos criados no modo binário em arquivos criados no modo ASCII.6 Exercícios 18. 18. o arquivo é recomposto e volta ao original.1 Refaça os exercícios 14.6 Escreva um programa que imprima o tamanho de um arquivo em bytes. ifstream ilpt2(“LPT2”). O nome do arquivo deve ser fornecido na linha de comando.3 Escreva um programa que continue o anterio e pegue os dados de um livro deste cadastro. 14. que tenha uma lista ligada de livros e estes dados sejam armazenados em um arquivo. salvando os dados em um arquivo. Crie uma função para retirar um livro do cadastro e apaga-lo do arquivo.18. 18. 18. 18. 20 linhas por 20 linhas.3. 5. automação da manufatura. Sn S1 S2 . CLP E1 E2 Interfaces CPU Entradas . em conformidade com um programa específico armazenado em memória interna (Figura 29). O CLP atende à funções de seqüênciamento e intertravamento elétricos por meio de comparações.Informática Industrial I DAS/UFSC 5 Controladores Lógicos Programáveis (CLP. PLC) 5...2 Áreas de aplicação Os CLPs encontram grande aplicação em quase todos os setores industriais envolvendo controle de processos.Configuração básica de um CLP. controle de subestações de energia. linhas de fabricação e montagem.. automação predial. Algumas aplicações usuais são: Marcelo Ricardo Stemmer 172 . chaves e sensores diversos e fornece sinais de saída que atuam sobre a máquina ou processo em questão. PROCESSO .... seqüênciamento e intertravamento de ações e supervisão do andamento de alguma atividade.. O principio de funcionamento é idêntico para todos os fabricantes: para exercer suas funções.1.1 Definição Define-se como CLP um equipamento eletrônico digital que tem como objetivo implementar funções específicas de controle e monitoração sobre variáveis de uma máquina ou processo por intermédio de módulos de entrada e saída. En Memorias Saidas . Figura 29 . podendo ser aplicado a todos os tipos de processos.1. integração de sistemas de automatização. onde quer que sejam requeridas funções de controle.1 Introdução aos CLPs 5. contagens. um CLP processa sinais de entrada provenientes de botoeiras. Todas as funções disponíveis devem poder ser programadas em uma memória interna e o hardware deve ser universal.. Os CLPs atuais são baseados em microprocessadores ou microcontroladores. temporizações e controle PID. química. tais como posição dos eixos. temperatura. petroquímica. Algumas datas importantes na evolução do CLP são mostradas a seguir: • 1968: projeto do primeiro CLP para a General Motors. vazão. aceleração e outras. pressão. velocidade. 5. de fácil expansão. • 1975: introdução do controlador PID analógico nos CLPs. • 1977: realização dos CLPs com microprocessadores em lugar de componentes discretos. uso da função de controlador PID para controle de grandezas físicas como posição. passando mais tarde a ter larga aplicação em todos os setores industriais. • 1971: primeira aplicação de CLPs fora da indústria automobilística. Marcelo Ricardo Stemmer 173 . O interesse inicial da indústria automobilística se deveu ao grande investimento necessário na alteração da lógica de comando das linhas de montagem implementadas com relês a cada alteração do modelo de carro fabricado. rotação.1. O primeiro usuário foi a General Motors. construção robusta. torque. 5. força. têxtil.2 Arquitetura dos CLPs A Figura 30 apresenta a arquitetura interna básica de um CLP. elevada confiabilidade. velocidade de avanço. para funções de intertravamento e seqüênciamento das operações e controle de grandezas relevantes para a usinagem. As principais vantagens dos CLPs sobre a lógica de relês são: • • • • • • redução do tempo de implementação e alteração de lógicas de controle e intertravamento devida à facilidade de programação e reprogramação. etc. Foram inicialmente aplicados na indústria automobilística. freqüentemente substituindo lógicas de comando originalmente implementadas com relês.Informática Industrial I • DAS/UFSC • • uso interno em máquinas-ferramenta. projeto modular. • 1978 em diante: CLPs ganham larga aceitação industrial. Todas as unidades são interligadas por meio de um barramento de endereços e um barramento de dados. controle do seqüênciamento e intertravamento das operações em linhas de produção e montagem automatizadas. pequenas dimensões e peso reduzido.3 Histórico Os CLPs foram originalmente inventados com a intenção de substituir lógicas de comando implementadas por meio de relês. usinas de geração de energia. potência e outras na indústria metal-mecânica. capacidade de comunicação com computadores e outros sistemas inteligentes (integração). baseado em componentes discretos. adequada a ambientes industriais. Os módulos de entrada. NEC V25. Os sinais com níveis de potência mais elevados são isolados com opto-acopladores. etc) Atuadores (reles. A Figura 31 apresenta um CLP com diversos módulos de entrada e saída. Estes são montados em um "rack" da aço nas proximidades dos equipamentos que deverão controlar. Os terminais de programação mais sofisticados incluem tela de vídeo. etc. que não ficam fixados no CLP exceto durante a entrada ou alteração de um programa. 80535. 8088. entre outros. integrados no mesmo "chip"). 8085. contactores. 80188. como: Z80. respectivamente. que constituem um sistema de aquisição de dados. solenóides e atuadores diversos. As saídas podem ser ainda temporizadas. chaves fim-de-curso. 8051. gravador de EPROM e software gráfico para programação e monitoração. I/O. 80196. em diferentes níveis de tensão e potência. termopares. etc) Processo Figura 30 . extensômetros. chaves. Laptops e Notebooks para esta finalidade. com regulagem para prover os retardos desejados. Os barramentos de dados e de endereços definem. etc. "encoders". sensores de proximidade. alojando em placas independentes os diversos componentes.Informática Industrial I DAS/UFSC Barramento de endereços Clock Processador RAM (EP)ROM Barramento de dados Interface serial Entradas Saidas CLP Terminal de programacao Sensores (botoes. O CLP é construído de forma modular. Os tipos mais freqüentemente utilizados são: 8031. etc. Os sinais de entrada e saída podem ser de corrente contínua ou alternada. Estes freqüentemente são equipamentos relativamente simples. sinais de fontes de tensão ou corrente. Antes de enviar ou receber dados de qualquer dispositivo ligado ao barramento de dados. que provê uma extensão dos barramentos internos de dados e endereços. Marcelo Ricardo Stemmer 174 . Alguns CLPs utilizam microprocessadores convencionais. O programa de operação do CLP é introduzido através de terminais de programação. dotados de teclado para entrada de dados e um display. Atualmente vem sendo cada vez mais usados computadores do tipo PC. Os módulos de saída fornecem sinais digitais ou analógicos devidamente codificados para energizar os dispositivos de operação e sinalização tais como contactores. o processador central tem que selecionar o endereço correspondente deste dispositivo no barramento de endereços. o caminho de troca de informações entre o processador e as demais unidades dos sistema e o endereço de acesso da cada unidade.Arquitetura interna dos CLPs. pressostatos. filtram e codificam sinais digitais e analógicos provenientes de botões. Os módulos são acoplados entre si por meio de um barramento. Os CLPs geralmente são baseados em microcontroladores (micro-processadores com timers. DMA. 1 Interfaceamento por meio das Entradas e Saídas do CLP O interfaceamento entre o operador e o CLP através de entradas e saídas digitais e analógicas do próprio CLP foi até pouco tempo o método mais utilizado na indústria para comunicação durante a operação "on-line".Informática Industrial I DAS/UFSC Figura 31 . apesar de sua inflexibilidade (Figura 32). 5. interligando o CLP a um computador (usualmente PC).CLP com módulos de expansão.3 Formas de interfaceamento Homem/Máquina para CLPs Para a utilização do CLP em qualquer instalação industrial. Na operação "off-line" é necessário permitir a entrada.3. 5. Figura 32 .Interfaceamento com operador via E/S do CLP. é necessário prover uma forma de interfaceamento entre este e o operador humano. Na operação "on-line". A comunicação entre o CLP e o operador pode ser executada basicamente de 4 maneiras: • • • • utilizando as entradas e saídas do próprio CLP. interligando o CLP a um Terminal de Programação (TP). deve ser possibilitada a entrada ou alteração de dados e comandos e a supervisão e visualização do andamento do processo sob controle do CLP. Cada uma destas formas de interfaceamento Homem / Máquina tem suas vantagens e desvantagens e oferece diferentes possibilidades de troca de informações e flexibilidade. utilizando painéis "inteligentes" dedicados. Marcelo Ricardo Stemmer 175 . tanto para a operação "on-line" quanto "offline" do mesmo. atualização e correção dos programas de aplicação que deverão rodar no CLP. etc. dimensões reduzidas e portabilidade. controle de pressão em caldeiras. encontrando aplicações tais como a introdução de parâmetros e de valores de referência para malhas de controle de temperatura e visualização dos mesmos em fornos industriais ou a introdução de coordenadas da localidade para onde um pallet deve ser enviado em um sistema automático de armazenamento e estocagem de materiais. a visualização da operação é feita por meio de lâmpadas. com tipicamente 9 teclas. tais como valores de referência para malhas de controle de temperatura em fornos industriais.3. que interliga as entradas e saídas aos dispositivos citados (chaves. controle da vazão de um determinado componente em uma válvula de uma instalação química. os painéis inteligentes são utilizados para comunicação "on-line". substituindo as ligações rígidas adotadas na técnica descrita anteriormente. Os painéis inteligentes apresentam as seguintes características: • • • • fácil introdução e visualização de dados. entre centenas de outras possíveis aplicações. uma alteração do programa. alterando o significado de uma tecla ou a forma de apresentação dos dados no display) através de reprogramação da EPROM. usualmente de uma até três linhas. Marcelo Ricardo Stemmer 176 . uma interface serial RS-232C e um microprocessador dedicado (8085. A mesma técnica é adotada para a supervisão e visualização do andamento do processo sendo controlado. com 3 fios). cujo estado será lido e levado em consideração pelo programa interno introduzido pelo operador no CLP. fácil alteração do modo de operação do painel inteligente (por exemplo. um display de cristal líquido. as entradas e saídas utilizadas para o interfaceamento com o operador não podem ser aproveitadas para o interfaceamento com o processo a controlar. botões. Além disso. Neste caso. Da mesma forma que no interfaceamento por meio das entradas e saídas do CLP. baseados em microprocessadores (Figura 33). etc). Da mesma forma. visando. LEDS. Z80. conectados à saídas pré-definidas do CLP. Nesta forma de interação. correção ou ampliação. chaves seletoras. LEDS. Este equipamento é conectado por meio da interface serial ao CLP e utilizado exclusivamente para a comunicação "on-line" entre o operador e o CLP.Informática Industrial I DAS/UFSC Esta técnica é utilizada para a entrada de dados. os dados são introduzidos por meio de botões. A desvantagem desta técnica é que qualquer alteração nas ligações de entrada e/ou saída implica necessariamente em uma alteração correspondente no programa interno do CLP. pode implicar na necessidade de alteração da fiação externa. uma EPROM. por exemplo. indicadores digitais ou analógicos. ou comandos do tipo ON/OFF. 5.2 Interfaceamento por meio de painéis inteligentes O desenvolvimento de módulos de interface serial tipo RS-232C para CLPs viabilizou a utilização dos chamados painéis "inteligentes" para a entrada de dados e visualização. ligados à entradas pré-definidas do CLP. etc. etc. uma otimização. potenciômetros. cablagem necessária para a interligação com o CLP mínima (um cabo de interface serial. etc). Alguns fabricantes dão a este dispositivo simplesmente o nome de “Interface”. uma pequena área de memória RAM. Estes equipamentos são compostos de um teclado simples. ligando ou desligando dispositivos comandados pelo CLP. 3. os TPs são dispositivos portáteis. como veremos no item seguinte (Figura 34). baseados em placas dedicadas de microprocessadores (os chamados "single-board computers") e montados em pequenas valises. de pequeno porte e peso e com bateria interna. Marcelo Ricardo Stemmer 177 .Informática Industrial I DAS/UFSC Figura 33 . Inicialmente. 5.Painel "Inteligente". também chamados Terminais Industriais TI).3 Interfaceamento por meio de Terminais de Programação (TP) Os chamados terminais de programação (TP. Os TPs foram concebidos para utilização diretamente no chão de fábrica.4 Interfaceamento por intermédio de computadores tipo PC / IC Devido a redução do custo dos computadores tipo PC. tem por finalidade principal permitir a introdução. Figura 34 . 5. de forma a garantir uma independência da existência de tomadas de energia nos locais de uso.3. alteração e depuração de programas de aplicação na memória do CLP. os TPs não passavam de painéis inteligentes com maior capacidade de memória e com teclado e display melhores. Além disto. estes vem sendo cada vez mais utilizados como dispositivos de programação e visualização para CLPs (ver Figura 34). Em função disto.Terminais de Programação para CLP. Atualmente verifica-se uma tendência de substitui-los por PCs de pequeno porte (LapTops e Notebooks). nos locais onde os CLPs estão instalados. Módulos de Comunicação: • interfaces RS232C. Os tipos mais usuais de módulos de E/S são: . não permitem freqüências de chaveamento muito altas. RS423 ou RS485 • interfaces para LANs (redes de computadores). Os módulos de saída podem ser realizados com 3 tecnologias básicas. • contadores de pulsos: usados na leitura de "encoders" digitais. . umidade. 5. óleo. • armazenamento de dados e programas do CLP em arquivos no disco do PC. etc. cada vez mais vantajosa. diretamente no chão de fábrica.sinal de corrente . • visualização do andamento do processo controlado pelo CLP na tela do PC (sistema supervisório). velocidade. • controle de motores de passo. RS422. posição. altas temperaturas (usualmente até 60ºC) e sobretensão (isolação galvânica). pressão. 4.Módulos de Entrada / Saída Analógicos: • 110V / 220V AC (±15%) – sinal de tensão • 0 a 5V DC / 0 a 10V DC/ ±10V DC – sinal de tensão • 4 a 20mA / 0 a 20mA . como adotam comutação mecânica (relê NA). interface serial e eventualmente um pequeno número de entradas e saídas.Módulos Especiais: • controlador PID: usados no controle de temperatura. 8. Estes módulos de E/S contém usualmente 2. • geração de relatórios: incluem interface para impressora. • entrada de dados e parâmetros "on-line" para o CLP por intermédio do PC. vazão. 16 ou 32 circuitos montados em caixas isoladas contra poeira. etc.4 Módulos de Entrada e Saída Além do módulo básico contendo a CPU.Módulos de Entrada / Saída Digitais: • 0 ou 5V DC (TTL) • 0 ou 12V DC • -12 ou +12V DC • 0 ou 24V DC .Informática Industrial I DAS/UFSC a crescente redução das dimensões e peso dos modernos Laptops e Notebooks torna sua aplicação em campo. incluindo a possibilidade de realização de cálculos complexos no PC e o envio dos resultados ao CLP. memórias RAM e EPROM. conforme ilustrado na Figura 35: • Saídas a relê: podem ser usadas em circuitos CA e CC. mas. medição de freqüência. o CLP pode ser expandido pelo acréscimo de novos módulos com entradas e saídas adicionais de diferentes tipos. • geração de relatórios e gráficos relativos ao andamento dos processos controlados pelo CLP no PC. Marcelo Ricardo Stemmer 178 . Modernos pacotes de software para CLPs em PCs incluem as possibilidades de: • programação gráfico-interativa. 000. ou programas de aplicação que não deverão sofrer alterações freqüentes. Memória EPROM e mais recentemente memória flash (EAPROM) é utilizada para os programas "permanentes". (b) A TRIAC. mas permitem comutação rápida. Grupo Utilização Memória do Sistema Monitor do CLP Área de Trabalho do Monitor Memória de Aplicação Tabela de E/S Tabela de Dados Programa de Aplicação Marcelo Ricardo Stemmer 179 .000.000 até aproximadamente U$80. optoacoplador RELE NA i eletroima Contato NA bobina (a) (b) (c) Figura 35 – Saídas: (a) A relê. pode-se classificar os CLPs em: • • • pequenos: até 256 E/S. Em função do número total de entradas e saídas efetivamente ligadas a um CLP através dos diversos módulos de expansão. com custo da ordem de U$300 a U$5. como o monitor do CLP.000.Informática Industrial I DAS/UFSC • • Saídas a TRIAC: também podem ser usados em circuitos CA e CC. A área de memória do CLP é usualmente subdividida como mostra a tabela a seguir. Saídas a Transistor coletor aberto: são usadas em circuitos CC e permitem comutação rápida.000 a U$30. com custo da ordem de U$30. grandes: mais de 1024 E/S. médios: 256 até 1024 E/S. com custo da ordem de U$5. 5.5 Organização interna de memória Os CLPs utilizam memória SRAM ou DRAM protegida por baterias para impedir a perda dos programas de aplicação e dos dados e parâmetros em caso de falta de energia de alimentação. (c) a transistor coletor aberto. temporizadores. Finalmente. a comunicação do CLP com dispositivos periféricos (tais como um TP. o CLP reinicia automaticamente a execução a partir da primeira linha de programa. por não sofrer alterações freqüentes (e só por parte do fabricante do CLP). S0001. no caso das entradas e saídas. Estes valores são constantemente atualizados em ciclos de varredura. constante.Tabelas de E/S e de dados. a varredura de entradas e saídas (input e output scan. O monitor. variáveis auxiliares (A) e operandos memória (M) não tem número de módulo ou porta. Durante o carregamento do programa aplicativo no CLP. etc. No exemplo. todas as entradas são lidas e seu estado copiado na área de memória reservada à tabela de entradas. porta 1.1 A0001 KM09. a área de programas de aplicação contém as instruções seqüenciais de controle definidas pelo usuário. constantes. As constantes (KM). A área de trabalho do monitor é o espaço de memória RAM onde são armazenados temporariamente os dados e variáveis utilizados para cálculos ou tarefas internas do monitor. Estes programas podem opcionalmente ser armazenados em EPROM ou EEPROM. armazenadas usualmente em RAM. um PC ou uma impressora) e o carregamento e supervisão dos programas de aplicação. memória. que permite a inicialização deste após ligar (incluindo a execução de auto-testes). na Figura 37) estão desabilitadas. pois não se referem a entradas ou saídas físicas do CLP. A tabela de E/S é uma área de memória RAM onde são armazenados os valores atuais das entradas e saídas do CLP. Estas variáveis e constantes utilizadas pelos programas aplicativos são usualmente designadas por símbolos alfanuméricos. A tabela de dados é uma área de RAM que inclui os dados e variáveis utilizados no programa de aplicação.6 Programação de CLPs 5.) e por números que. e o CLP não se encontra no Run Mode (modo “execução”). 5. Da mesma forma. Durante um ciclo de varredura. Desta forma. compostos de uma ou mais letras indicando o tipo de dado (entrada. como indicado na Figura 36. O fluxograma da Figura 37 representa a operação básica dos ciclos de varredura. tais como valores atuais de contadores. caso as alterações esperadas sejam pouco freqüentes. RAM Tabela I/O { Tabela Saída Tabela Entrada Dados aplicação S0001.81 M0001 Figura 36 . em cada ciclo a tabela de saídas é varrida e seu conteúdo é copiado nas saídas físicas do CLP.1 E0002.Informática Industrial I DAS/UFSC O Monitor é uma espécie de "sistema operacional" simplificado do CLP.6.1 designa uma saída pertencente ao módulo 0001. saída. indicam o módulo e a porta correspondentes. um painel inteligente. Estas funções são habilitadas pelo programa monitor do CLP somente quando Marcelo Ricardo Stemmer 180 . é armazenado em memória EPROM.1 Introdução Os programas de um CLP são sempre executados de forma cíclica (isto é. Cada execução completa das linhas que compõe uma lógica programada no CLP é chamada um “ciclo de varredura”. os tempos de execução dos programas de aplicação apresentam uma variação mínima. em "loop"): após a execução da última instrução. etc. paridade. período de interrupções. se houver Figura 37 – O ciclo de varredura de um CLP. pode-se realizar o carregamento do programa de aplicação . : retentividade).ex. • Parâmetros gerais: tipo de CPU. etc Após o carregamento do arquivo de configuração. • Descrição dos operandos: número e tipo dos operandos e suas características (p.na memória de trabalho do CLP. O CLP necessita ser configurado antes da utilização. A configuração é feita através do carregamento de um arquivo especial de configuração. • Parâmetros de Comunicação em Rede: taxa de transmissão. etc. Preparação da verredura e atualização dos timers N Housekeeping IO Enabled Input Scan Run Mode N User Program IO Enabled N Output Scan Programmer Communication System Communications User Programm Checksum Comunicação com o TP. contendo as seguintes informações: • Descrição do barramento de Módulos de E/S: número e tipo das entradas e saídas. O programa aplicativo é desenvolvido dentro de um “ambiente de desenvolvimento” fornecido pelo fabricante do CLP e que roda no TP (usualmente um computador tipo PC ou IC). Marcelo Ricardo Stemmer 181 . endereço em rede.Informática Industrial I DAS/UFSC houver um programa de aplicação válido na memória de trabalho e o CLP estiver corretamente configurado. se conectado Comunicação com outros equipamentos via rede. a Disjunção (função lógica "OU") e a Negação (função lógica "NÃO"). que é a técnica usada nos CLPs. Para elaborar a lógica de comando a ser implementada. ou por meio de Software. Na álgebra booleana. +12V e 12V. cujos valores reais podem ser de 0V e +5V. NOT. Programação baseada no Diagrama de Escada (ou "Ladder Diagramm" . Qualquer que seja a técnica de programação adotada. usando portas lógicas digitais ou relês. A linguagem permite simultaneamente a programação e a verificação da correção lógica do programa (validação).x2. XOR. 0V e +24V. Todas as portas lógicas operam com dois níveis básicos de tensão. ao contrário da álgebra convencional. faremos a seguir uma breve revisão de álgebra de Boole. etc. Os dois primeiros tipos de linguagens de programação que examinaremos são fortemente baseadas na conversão das expressões lógicas booleanas em programas para o CLP. o programa de aplicação é traduzido pelo terminal de programação ou PC na linguagem de máquina do processador utilizado no CLP e carregada neste via interface serial. respectivamente.Informática Industrial I DAS/UFSC A programação de um CLP é a maneira pela qual o usuário define as relações existentes entre os sinais de entrada e de saída. Em função disto.6. -5V e +5V. que é lida como y igual a x1 E x2. 5. que serão apresentados mais adiante. As linguagens de programação deste tipo se assemelham bastante com as linguagens de máquina de microprocessadores (assembly) . que a torna mais adequada que as anteriores para a implementação de lógicas complexas. que expressa os possíveis valores da variável de saída para todos os valores possíveis das variáveis de entrada. Programação em GRAFCET (ou "Sequential Function Chart" . A tabela da verdade para a conjunção é a seguinte: Marcelo Ricardo Stemmer 182 . A álgebra booleana é uma forma de lógica simbólica que mostra como estas portas lógicas operam. Estas combinações são utilizadas para representar expressões booleanas da forma: • Conjunção: y = x1. faz-se uso da álgebra booleana. correspondentes a tensão "baixa" e a tensão "alta" das portas lógicas. A conjunção pode ser representada na forma de uma "tabela de verdade". a partir da qual é gerado o programa. É possível identificar na maior parte dos CLPs existentes no mercado três formas mais difundidas de programação: • • • Programação a partir de operadores lógicos (ou "Instruction List" . etc. A programação é realizada de forma gráfico-interativa e o programa resultante tem a forma dos chamados "diagramas de escada" ou "diagramas de relês".LD): esta linguagem foi criada para facilitar a implantação no CLP de lógicas originalmente realizadas com relês. uma variável pode assumir somente dois valores possíveis.SFC): a linguagem GRAFCET (GRAFo de Comando Etapa-Transição) representa um método moderno de programação baseado na técnica das redes de Petri. Existem três combinações básicas entre variáveis lógicas booleanas: a Conjunção (função lógica "E"). denominados genericamente como nível "baixo" e nível "alto". OR. representados por "0" e "1". A implementação prática das expressões booleanas pode ser feita por Hardware. Se a lógica foi originalmente implementada com relês (situação freqüentemente encontrada na prática) é preciso obter a função lógica booleana associada.2 Revisão de álgebra booleana Os sistemas digitais tem como bloco construtor básico as chamadas portas lógicas binárias.IL): a lógica de comando é representada na forma de operadores booleanos do tipo AND. a disjunção pode ser expressa na forma de uma tabela da verdade: X1 0 0 1 1 x2 0 1 0 1 y 0 1 1 1 • Negação: y = x 1.x = x (5. x = 0 2 (6.Leis de "De Morgan" x1 .leis da negação: x.x3 (3.0 = 0 (8.a) x1+x2 = x2+x1 (1.b) . que é lida como y igual a NÃO x.leis distributivas: x1.x3 = (x1+x2).Operações com 0 e 1: x.Informática Industrial I DAS/UFSC x1 0 0 1 1 x2 0 1 0 1 y 0 0 0 1 • Disjunção: y = x1 + x2.a) x1 + x 2 = x1. onde várias das combinações básicas citadas podem ser utilizadas.leis comutativas: x1.x2 = x1 (4.c) .b) .x1 (1.(x1+x3) (3.Negação simples: 0 = 1 7 (9.b) .b) . x2 = x1 + x2 3 (7.x3) = (x1. que é lida como y igual a x1 OU x2.x3 (2.a) 1 = 0 8 (9.x2).d) Marcelo Ricardo Stemmer 183 . Da mesma forma que a conjunção.x2 5 (7.b) .1 = x (8.(x2+x3) = x1. foram definidos por Boole os seguintes teoremas (hoje conhecidos como leis de Boole): .a) x1+(x2+x3) = (x1+x2)+x3 (2.x2 = x2.(x2.leis da absorção: x1.tautologia: x.(x1+x2) = x1 (4.leis associativas: x1.a) x+x = x (5.b) (x)= x6 (6.c) x+1 = 1 (8.a) x1+x2.a) x.b) .x2+x1.b) .a) x + x = 14 (6.b) x+0 = x (8. A tabela da verdade é: x 0 1 y 1 0 Para calcular o resultado de expressões lógicas booleanas mais complexas.a) x1+x1. A expressão booleana assim obtida é dita "de termos mínimos". isto é: y = x1. A implementação prática das expressões booleanas pode ser feita por Hardware.x3 . • Passo 3: finalmente. O processo de obtenção da expressão booleana a partir da tabela de verdade se compõe de três passos: • Passo 1: procura-se na tabela da verdade todas as linhas cujas saídas tenham valor lógico 1.x 2 . representando as entradas com valor lógico 1 por xi e as com valor lógico 0 por xi . ou por meio de Software. obtemos: y = ( x1 + x2 ).x 3 + x1 . Marcelo Ricardo Stemmer 184 .x3 Passo 3: a função procurada (expressão booleana de termos mínimos) é dada pela disjunção das expressões acima.x 2.x 3 Linha 7: x1 . Dada a tabela da verdade abaixo: Linha 1 2 3 4 5 6 7 8 x1 0 0 0 0 1 1 1 1 x2 0 0 1 1 0 0 1 1 x3 0 1 0 1 0 1 0 1 y 0 0 1 0 1 0 1 0 - - Passo 1: As linhas cujas saídas tem valor lógico 1 são a 3. • Passo 2: para cada uma destas linhas obtém-se a conjunção ("E") de todas as variáveis de entrada. a expressão booleana procurada é dada pela disjunção ("OU") das expressões parciais obtidas no passo anterior.Informática Industrial I DAS/UFSC A implementação prática de lógicas combinacionais booleanas é freqüentemente realizada por meio de tabelas da verdade. A partir desta tabela da verdade é obtida a expressão booleana que a representa. a 5 e a 7 Passo 2: obtemos as seguintes expressões parciais: Linha 3: x1.x 2. O mesmo resultado pode ser obtido de forma mais fácil por meio de uma ferramenta de apoio conhecida como Diagrama de Karnaugh [10].b. que exprimem o comportamento desejado das saídas do sistema para um dado conjunto de valores de entrada.x 2 .x 3 + x1 . As leis de Boole podem agora ser utilizadas para simplificar a expressão obtida.b sobre a equação anterior. Usando as leis 3. usando portas lógicas digitais ou relês. 6.x2 .a e 3.x 3 Linha 5: x1 . Os dois primeiros tipos de linguagens de programação que examinaremos são essencialmente baseadas na conversão das expressões lógicas obtidas da forma acima descrita em programas para o CLP.a. O processo acima pode ser visualizado no seguinte exemplo.x 2 . que não abordaremos aqui. 8.x 3 . que é a técnica usada nos CLPs. lista de instruções). que representam as operações lógicas booleanas e comandos de transferência de dados. Uma linguagem completa inclui ainda mnemônicos para realizar comparações do tipo >.R <operando> : reseta operando em 0. . Marcelo Ricardo Stemmer 185 . uma entrada do CLP). . mas agora estes serão padronizados pela norma IEC 1131 sob o nome de IL (Instruction List.E <operando> : executa uma operação lógica "E" entre o acumulador do microprocessador do CLP e o operando indicado como parâmetro.TEM <valor> : executa um retardo com temporização definida pelo valor indicado.S <operando> : seta operando em 1. se o conteúdo do acumulador for 1. <. definição de variáveis.3.ARMN <operando> : armazena conteúdo negado do acumulador no operando indicado.6.ARM <operando> : armazena conteúdo do acumulador no operando indicado.3 Instruction List (IL) 5. se o conteúdo do acumulador for 1 (este operando pode ser. .CAR <operando> : carrega conteúdo do operando no acumulador (este operando pode ser.OUN <operando> : executa uma operação lógica "OU" entre o acumulador e a negação do operando. >=.CARN <operando> : carrega conteúdo negado do operando no acumulador. .1 Introdução A linguagem IL define uma série de mnemônicos semelhantes a linguagem "assembly" (linguagem de máquina dos microprocessadores). etc. . . Até bem recentemente cada fabricante oferecia seu próprio conjunto de mnemônicos.X3+X4).OU <operando> : executa uma operação lógica "OU" entre o acumulador e o operando indicado como parâmetro. <=. .6.6.2 Elementos básicos Um possível repertório básico de comandos poderia ter a seguinte forma: . Os comandos propostos acima podem ser utilizados para a programação de uma lógica de comando implementada originalmente com portas lógicas digitais.EN <operando> : executa uma operação lógica "E" entre o acumulador e a negação do operando. como a apresentada na Figura 38. As equações booleanas equivalentes são também mostradas na figura. por exemplo.X5 X4 Not S1 And X1 S1 And X5 Not S2 S3 Figura 38 .3. X2 And X3 Or S1=(X2. . uma saída do CLP). . =. 5. por exemplo. contadores. deslocamentos (shifts) à esquerda e à direita.Lógica de comando com portas lógicas digitais.X1 S2=S3=S1. .Informática Industrial I DAS/UFSC 5. Alguns comandos básicos desta linguagem estão representados na tabela a seguir a título de exemplo. acumulador = acumulador AND NOT x5 ARM s2 . armazena acumulador em s1 EN x5 .6. armazena acumulador em s2 ARM s3 . da Siemens AG.Informática Industrial I DAS/UFSC O programa para implementar estas equações no CLP teria a seguinte forma: CAR x2 . acumulador = acumulador OR NOT x4 E x1 . Uma referência completa pode ser encontrada em [9].3. conforme mostrado na Figura 39. Definem-se as seguintes entradas e saídas para executar o comando: Marcelo Ricardo Stemmer 186 . acumulador = acumulador AND x1 ARM s1 . armazena acumulador em s3 Um exemplo prático de linguagem baseada em operadores lógicos booleanos é a STEP-5.3 Exemplo de programação em IL Deseja-se implementar uma parte da lógica de comando de uma furadeira em IL. coloca x2 no acumulador E x3 . Observe que os mnemônicos estão em alemão. Grupo operadores lógicos Operação U UN O ON S R S R FR ZV ZR P PN SU RU L T LC = < > >< <= >= + x : SPA SPB SLW SRW RLD RRD Descrição lógico E (Und) lógico E NÃO (Und Nicht) lógico OU (Oder) lógico OU NÃO (Oder Nicht) Seta E/S/Variável Reseta E/S/Variável Seta contador Reseta contador libera contador (Freizesten) contagem p/ frente contagem p/ trás Testa se bit = 1 (Pruefen) Testa se bit = 0 Seta incondicional Reseta incond. acumulador = acumulador AND x3 OUN x4 . Carrega (Laden) Transfere (Transferieren) Carrega codificado igual menor maior diferente menor ou igual maior ou igual adiciona subtrai multiplica divide Pula absoluto (Springe Absolut) Pula condicional (Springe Bedingt) Desloca a esquerda Desloca a direita rotaciona a esquerda rotaciona a direita Memória Contadores teste de bits carregar e transferir Comparações operações matemáticas Pulos Deslocamento 5. SE avanço lento com rotação ligado . E profundidade de perfuração atingida . ENTÃO liga avanço rápido . . ligar avanço rápido (y1) até atingir o ponto de redução (x3). .x4: profundidade de perfuração alcançada. . Ao atingir a profundidade de perfuração desejada (x4). E ponto de redução atingido . e liga retrocesso rápido . até retornar a posição de partida (x2).Comando de uma furadeira.Informática Industrial I DAS/UFSC Ponto de partida Ponto de redução Profundidade de perfuração Figura 39 . e liga avanço lento com rotação . Neste ponto. desligar o avanço rápido (y1) e ligar o avanço lento com rotação (y2). ENTÃO desliga avanço lento com rotação . desliga retrocesso rápido Marcelo Ricardo Stemmer 187 . SE avanço rápido ligado .y2: ligar/desligar avanço lento com rotação. Sinais de Saída: . A operação básica é a seguinte: se a furadeira estiver na posição de partida (x2) e um comando de partida (x1) foi dado. Sinais de Entrada: . E posição de partida .x1: comando de partida (operador). E posição de partida atingida . ENTÃO desliga avanço rápido . SE retrocesso rápido ligado . tem a forma seguinte: CAR x1 E x2 S y1 CAR y1 E x3 R y1 S y2 CAR y2 E x4 R y2 S y3 CAR y3 E x2 R y3 . . A lógica de comando acima.x2: furadeira na posição de partida.y3: ligar/desligar retrocesso rápido.x3: ponto de redução alcançado.y1: ligar/desligar avanço rápido. . SE comando de partida . desligar o avanço lento com rotação (y2) e ligar o retrocesso rápido (y3). após convertida em programa (IL). Relês e elementos básicos de Diagramas de Escada. por um padrão característico conhecido como "Diagrama de Escada" ou "Diagrama de Relês".2 Elementos básicos do LD Os diagramas de escada baseiam-se fundamentalmente em três símbolos básicos (Figura 40). como veremos a seguir.6.4 Ladder Diagramm (LD) 5. • necessidade de uma certa familiarização com programação em assembly. 5. que mantém os contatos de saída abertos (OFF) enquanto não houver corrente na bobina de entrada. que mantém os contatos de saída fechados (ON) enquanto não houver corrente na bobina de entrada. que representam alguma função lógica de controle. as Bobinas propriamente ditas.1 Introdução A lógica de controle a relês costuma ser representada. Como muitos engenheiros e técnicos estavam acostumados a trabalhar com lógica de reles.4. foi criada uma linguagem para CLP que procura simular um diagrama de reles real. Um diagrama de escada corresponde à associação de elementos de entrada e saída.6. podemos citar: • necessidade de familiarização do operador com álgebra booleana. Como desvantagens. nos meios industriais.4. • alterações trabalhosas nas lógicas já implementadas. 5.Informática Industrial I DAS/UFSC 5. • documentação mais compacta do que a equivalente com relês.4 Vantagens e desvantagens da técnica Como vantagens desta forma de programação temos: • correspondência entre comandos da linguagem e as instruções assembly do processador. que correspondem a sinais de saída. Relês Normalmente Fechados (NF).6.3. Marcelo Ricardo Stemmer 188 .6. RELE NA RELE NF i eletroima Contato NA i eletroima Contato NF bobina bobina Rele NA Bobina Rele NF Figura 40 . facilitando uma estimativa do tempo de execução do programa. representando: • • • Relês Normalmente Abertos (NA). (b) em diagrama de escada. Além destes elementos básicos. somente haverá sinal na saída do conjunto (estado lógico "1") quando as bobinas de entrada de ambos os relês estiverem ativadas (isto é. Esta associação é representada em Diagrama de Escada da forma mostrada na Figura 41.Informática Industrial I DAS/UFSC Os relês NA e NF correspondem à variáveis de entrada do CLP. conforme mostrado na Figura 41. Es Ss Ss Saida = 1 Se Ec1 = 1 E Ec2 = 1 a) Ec Ec RELE 1 RELE 2 b) RELE 1 RELE 2 Figura 41 . uma função lógica "OU" é representada pela associação em paralelo de relês. Es Ss Saida = 1 Se Ec1 = 1 OU Ec2 = 1 Ec a) RELE 1 b) RELE 1 RELE 2 Ec RELE 2 Figura 42 .Lógica "OU": (a) com relês. A representação equivalente em Diagrama de Escada é mostrada na Figura 42. contadores e outros elementos especiais de entrada e saída. Nesta situação. A cada elemento no diagrama de escada é usualmente associado um identificador composto por letras e números. Uma função lógica "E" é representada pela associação em série de relês. conforme a Figura 42.a. enquanto as bobinas representam elementos de saída do mesmo. Marcelo Ricardo Stemmer 189 .b. existem representações próprias para temporizadores.Lógica "E": (a) com relês. tiverem também um estado lógico "1"). De forma análoga.b. (b) em diagrama de escada.a. Aqui teremos sinal na saída do conjunto (lógico "1") quando ao menos uma das bobinas dos relês estiver ativada (também lógico "1"). Es Ss Es Ss Ss Ec a) Ec Ec RELE 3 RELE 1 RELE 2 b) RELE 1 RELE 2 Bobina Figura 43 . Bobina T Temporizador Figura 44 . Bobina Saida complementada. Abertura de ramo paralelo Entrada.Informática Industrial I DAS/UFSC Um relê NF indica uma negação do sinal de entrada correspondente. uma vez que haverá sinal na saída do mesmo (lógico "1") quando não houver sinal na bobina de entrada (lógico "0"). ativando um elemento externo (Figura 43).4. como os mostrados na Figura 44.3 Estrutura de um programa em LD A linguagem de programação baseada no diagrama de escada (LD) é composta por um conjunto de símbolos gráficos.Ligação em série de uma bobina. como em um circuito a reles real. O número de instruções simbólicas que podem fazer parte de cada lógica varia muito de um modelo de CLP para outro. não havendo portanto. que são sempre colocadas entre uma barra vertical de entrada (sempre a esquerda do diagrama) e uma barra vertical de saída (sempre a direita do diagrama). com os quais é possível representar uma grande variedade de estruturas. Os símbolos são interligados entre si para representar lógicas.Exemplos de símbolos gráficos do Diagrama de Escada (LD) Um programa em LD é composto de uma ou mais lógicas. (b) Diagrama Escada. Rele NF Rele de Pulso Saida. Marcelo Ricardo Stemmer 190 .6. Estas barras representam barras de energia. 5. Uma bobina ligada em série com um conjunto de relês indica que um determinado sinal de saída será ativado quando os relês associados permitirem a passagem de corrente até a referida bobina. caminhos de fuga de corrente. sendo que o fluxo simulado de corrente elétrica vai sempre somente da barra esquerda para a direita. (a) Relês. Rele NA Fechamento do ultimo ramo paralelo aberto Entrada. 1 Barra de Entrada (esquerda) 2 3 4 5 6 . instruções e operandos. ligações verticais: permitem interligar células em paralelo. Marcelo Ricardo Stemmer 191 . operação ou Figura 45 . Programas compostos de várias lógicas são executados de cima para baixo. • blocos de função: grande variedade de elementos adicionais. transferindo o estado lógico de uma célula a outra. os elementos de uma linguagem de relês são geralmente dispostos sobre uma matriz com número limitado de células (Figura 45). que podem ser: • elementos de decisão: contatos NA e NF que refletem o estado lógico das entradas do CLP. • elementos de operação: bobinas dos relês. definindo uma função "OU" do estado lógico destas. simulando as linhas de alimentação do circuito.. X1 lógica 0 X2 X3 S1 X4 S2 lógica 1 S1 = (x2. seqüênciadores. etc.x5 S1 X5 S3 Barra Entrada Barra Saida Figura 46 .x3+x4).. e repetidos ciclicamente após a execução da última lógica.formato de uma lógica. O programa correspondente para CLP seria composto de 2 lógicas. reles de pulso. na seqüência mostrada pela numeração colocada dentro das células na Figura 45. ligações horizontais: representam ligações elétricas entre células. definindo funções como contadores. bobinas auxiliares. uma em cada extremo da matriz. cujos estados lógicos são alterados em função do resultado da lógica e jogados nas saídas. que podem ser: • • • • barras de alimentação: barras verticais. Barra de Saída (direita) Células com elementos de decisão.Exemplo de Diagrama de Escada. Cada lógica é processada coluna por coluna.x1 S2 = S3 = S1.Informática Industrial I DAS/UFSC Assim. uma lógica após a outra. a lógica de comando apresentada anteriormente para o circuito lógico digital (Figura 38) seria representada em Diagrama de Escada conforme mostra a Figura 46. operações aritméticas. A título de exemplo. 6. etc. D/A.Informática Industrial I DAS/UFSC Para a entrada do programa sob a forma de Diagrama de Escada no CLP.: KM+9. multiplicar e dividir operadores. Binário/Decimal e Decimal/Binário. Ex..4 (saída 4 do bloco 0001). maior. Existem 3 tipos básicos de operandos: • operandos simples: contém o valor atual de uma entrada (relê). Ex. • comunicação: envio e recepção de mensagens via rede. 5.: TM0026. • conversão: operações de conversão A/D. aritméticas: permitem somar. etc). Esta última opção vem sendo preferida nos anos recentes. que tem seu valor conservado mesmo após o desligamento do CLP ou queda de energia. saída (bobina) ou posição de memória (relê auxiliar ou número real de ponto flutuante) do CLP. . As instruções são utilizadas para executar determinadas tarefas por meio de leitura e/ou alteração do valor dos operandos já vistos. menor. São identificados de forma semelhante aos casos anteriores. As instruções podem ser subdivididas em grupos. OU e OU exclusivo entre operadores. contagem bidirecional (incremental / decremental) e temporização (delay). • operandos tabela ou vetor: são arranjos (arrays) de operandos simples.3 (entrada 3 do bloco 0002) ou S0001. Para uma referência completa recomendamos a leitura do manual próprio do fabricante do CLP em uso. Todas estas instruções tem sua representação gráfica em LD. binárias: operações E. Exemplos de operadores são os pontos de entrada e saída e as memórias contadoras. A maioria dos CLPs atuais permite a definição de alguns operandos como retentivos. contadores: operações de contagem simples (incremental). (Ex. Veremos a seguir exemplos de algumas delas. memória para saída. o terminal de programação pode possuir um teclado dedicado com os símbolos acima indicados ou permitir a programação por meio de recursos gráficos de edição no vídeo. pois é adequada para a programação usando um computador tipo PC ligado ao CLP. • • • • • Marcelo Ricardo Stemmer 192 .81 ou #9. São também identificados no programa por meio de códigos alfanuméricos. • teste: operações de comparação (igual. subtrair.: E0002.4 Operandos e Instruções de LD Os operandos identificam variáveis e constantes utilizadas no programa aplicativo. isto é. • operandos constantes: são utilizados para definir valores fixos durante todo o programa.Instruções tipo Relê: As instruções mais usuais sobre relês (NA e NF) já foram exemplificadas anteriormente.81). São identificados no programa por códigos alfanuméricos. como segue: relês: leitura de valores de contatos e ajuste de valores de bobinas.4. movimentadores: movimentam entrada para memória. A saída “não limite” é mantida ativada enquanto nenhum dos limites é atingido. . que indica quantas lógicas devem ser puladas se a bobina de salto for ativada. O primeiro operador define o valor da contagem. A saída “limite superior” é ativada quando o primeiro operando (contador) assume valor igual ao terceiro operando (limite de contagem). • bobina “liga”: seu estado vai para 1 se o resultado da lógica que a antecede for verdadeiro (linha energizada). cada transição de 0 para 1 na entrada “incrementa” faz com que o operando “contador” seja incrementado em um passo. A saída “limite inferior” é ativada quando o contador chega em zero. Uma transição de 0 para 1 na entrada “decrementa” tem o efeito oposto.Instruções tipo Contador: A instrução tipo Contador Simples (unidirecional) requer 2 operadores. • bobina de salto: não é realmente uma saída. A instrução tipo Contador Bidirecional (incremental / decremental) pede 3 operadores. Marcelo Ricardo Stemmer 193 . Este tipo de bobina é associado a uma constante. • bobina “desliga”: seu estado vai para 0 se o resultado da lógica que a antecede for verdadeiro (linha energizada).Informática Industrial I DAS/UFSC Um tipo útil de instrução relê ainda não mencionada é o relê de pulso. A contagem para quando o limite definido pelo outro operando é atingido. cada transição de 0 para 1 na entrada “incremento” aumenta o valor do contador em 1. Se houver um sinal lógico 1 na entrada “habilita”. não ocorre nada. O segundo operador define o passo da contagem (valor do incremento ou decremento). incremento op1: contagem limite atingido habilita op2: limite (cte) limite não atingido Figura 47 . não ocorre nada. 2 sinais de entrada e 2 de saída (Figura 47). Se houver um sinal lógico 1 na entrada “habilita”. mas uma forma de implementar um salto (jump) na seqüência de execução do programa. O relê de pulso coloca a saída em 1 durante um único ciclo de varredura do programa quando a sua entrada passa de 0 para 1. As bobinas podem ser de 4 tipos básicos diferentes: • bobina simples: seu estado é sempre igual ao resultado da lógica que a antecede (0 se linha desenergizada e 1 se linha energizada).Contador simples. O terceiro operador contém o valor limite superior de contagem (o valor limite inferior é sempre zero). a saída “limite atingido” vai para 1. Quando isto ocorre. caso contrário. como as demais. caso contrário. Veremos uma aplicação disto mais a frente. A saída “limite não atingido” é oposta a anterior. 3 sinais de entrada e 3 de saída (Figura 48). Um dos operadores armazena o valor da contagem enquanto o outro define um valor limite para a mesma (este limite é uma constante). Informática Industrial I DAS/UFSC incrementa decrementa op1: contagem op2: passo habilita op3: limite (cte) limite superior não limite limite inferior Figura 48 - Contador Bidirecional. Uma instrução semelhante é utilizada para gerar delays. Para implementar um atraso, utilizase uma instrução temporizadora. O Temporizador ativa (i.é, coloca em 1) a saída “tempo atingido” T segundos (ou outra unidade de tempo especificada pelo fabricante) após a ativação de sua entrada “libera“ (Figura 49) . É necessário energizar também a entrada “habilita”, senão o contador de tempo é zerado. Usualmente as entradas “libera” e “habilita” são conectadas juntas. libera op1: contagem tempo tempo atingido habilita op2: tempo limite tempo não atingido Figura 49 – Temporizador. - instruções aritméticas: A soma requer 3 operandos: 2 deles contém as parcelas a serem somadas e o terceiro contém o resultado da soma (Figura 50). A operação só é realizada quando a entrada “habilita” é ativada. A saída “estouro” é ativada se a soma é maior do que a capacidade do terceiro operando. A multiplicação é muito semelhante, usando também 3 operandos: o primeiro é o multiplicando, o segundo é o multiplicador e o terceiro é o resultado. Também são usadas as mesmas saídas que na soma. habilita MUL / SOM op1: parcela 1 op2: parcela 2 op3: resultado estouro cópia entrada Figura 50 - Soma e Multiplicação. Marcelo Ricardo Stemmer 194 Informática Industrial I DAS/UFSC A subtração também pede 3 operandos: 2 contendo as parcelas da subtração e o terceiro contendo o resultado (Figura 51). São usadas 3 saídas, que indicam o sinal do resultado. A operação só é realizada quando a entrada “habilita” é ativada. habilita SUB op1: parcela 1 op2: parcela 2 op3: sub op1-op2 res < 0 res >0 res = 0 Figura 51 – Subtração. A divisão pede 4 operandos: o dividendo, o divisor, o quociente e o resto (Figura 52). A operação só se realiza quando a entrada “habilita” é ativada. A saída “divisão por zero” é ativada se o divisor (segundo operando) for zero. Neste caso, o resto será colocado em zero. habilita DIV op1: dividendo op2: divisor op3: quociente op4: resto cópia entrada divisão por zero Figura 52 – Divisão. - instruções binárias: As operações binárias AND, OR e XOR (OU EXCLUSIVO) pedem 3 operandos: 2 operandos contendo os valores a combinar e um terceiro contendo o resultado (Figura 53). Assim, o terceiro operando conterá (Op1 AND Op2), (Op1 OR Op2) ou (Op1 XOR Op2), conforme a escolha. A operação só é realizada se a entrada “habilita” estiver ativada. habilita AND/OR/XOR op1 op2 op3: resultado cópia entrada Figura 53 - Operações OR, XOR, AND. Marcelo Ricardo Stemmer 195 Informática Industrial I DAS/UFSC 5.6.4.5 Diagramas equivalentes Alguns diagramas não podem ser representados diretamente com este tipo de simbologia. Tais diagramas são os que apresentam diversos caminhos para acionar uma determinada saída. Um exemplo desta situação é apresentado na Figura 54. X1 X2 S1 X5 X3 X4 S1 = (X1.X2)+ (X1.X5.X4)+ (X3.X4)+ (X3.X5.X2) Barra Entrada Barra Saida Figura 54 - Diagrama não representável no CLP. Em tais situações, o programador deve converter a estrutura proibida para uma equivalente que possa ser representada utilizando os recursos da linguagem. Tais transformações geralmente resultam em um diagrama com mais elementos do que o original. Para o exemplo anterior, a representação equivalente é mostrada na Figura 55, que apresenta as mesmas equações booleanas que as do diagrama original. X3 X5 X2 S1 S1 = (X3.X5+X1).X2+ (X1.X5+X3).X4 S1 = (X1.X2)+ (X1.X5.X4)+ (X3.X4)+ (X3.X5.X2) X1 X1 X5 X4 X3 Barra Entrada Barra Saida Figura 55 - Diagrama equivalente ao exemplo anterior. Marcelo Ricardo Stemmer 196 Informática Industrial I DAS/UFSC 5.6.4.6 Exemplos de programação em LD - Exemplo 1: Comando de uma Sinaleira Deseja-se implementar o comando de uma sinaleira que controla o tráfego em um cruzamento de duas ruas de mão única por meio de um CLP, conforme mostra a Figura 56. CLP Figura 56 - Cruzamento com sinaleiras. A seqüência de comando a implementar é a apresentada na tabela abaixo. Estado 1 2 3 4 Sinaleira A Vermelho Vermelho Verde Verde/ Amarelo Sinaleira B Verde Verde/ Amarelo Vermelho Vermelho Temporização 40 seg. 10 seg. 40 seg. 10 seg. As conexões correspondentes às entradas e saídas no CLP são mostradas na tabela a seguir. Número da E/S no CLP Entrada 0 Saída 10 Saída 11 Saída 12 Saída 15 Saída 16 Saída 17 Função na sinaleira Habilita Sinaleiras Sinaleira A Vermelha Sinaleira A Amarela Sinaleira A Verde Sinaleira B Vermelha Sinaleira B Amarela Sinaleira B Verde Conexão Externa Chave ON/OFF Lâmpada Lâmpada Lâmpada Lâmpada Lâmpada Lâmpada Para o exemplo em estudo, o diagrama em escada equivalente (LD) a ser programado no CLP é mostrado na Figura 57. Marcelo Ricardo Stemmer 197 acrescidos de duas lógicas adicionais para o inicio de operação (quando a sinaleira é ligada) e para o término de operação (quando a sinaleira é desligada). O relê de pulso impede que a lógica 1 seja repetida em cada ciclo de varredura (o que seria indesejável. todas as lógicas que compõe e programa serão executadas milhares de vezes enquanto a sinaleira passa uma única vez pelos 4 estados previstos. a sinaleira foi programada para ir para o estado 1 no momento em que for ligada (indicado como “partida” na Figura 57). retornando a primeira lógica após cada ciclo de varredura (cuja duração é de apenas alguns milissegundos). Marcelo Ricardo Stemmer 198 . O relê de pulso mantém a saída em 1 somente durante o ciclo de varredura imediatamente após o ligamento da sinaleira. E0 S10 S17 S10 S12 S15 S17 S16 S15 S16 S17 S10 S12 S11 Estado 4 L D D D L P LS L L D P artida (Estado 1) E0 D D D Estado Desligado S17 40s S16 10s L Estado 2 L D D D L Estado 3 S12 40s S11 10s L S10 S11 S12 S15 S17 Estado 1 Figura 57 . ajustados com os tempos desejados de duração de cada estado. Lembre-se que o programa representado pelo diagrama de escada da Figura 57 será executado de forma cíclica.Informática Industrial I DAS/UFSC Observe que teremos basicamente uma lógica para cada um dos quatro estados da tabela 3. que pode ser visto na lógica 1. além dos relês NA e NF e bobinas liga e desliga. mesmo que a chave conectada a entrada E0 do CLP continue ligada.Diagrama de Escada para o comando da sinaleira. Nesta aplicação. Desta forma. e um relê de pulso (PLS). foram utilizados temporizadores. produzindo assim o efeito desejado. No nosso exemplo. pois ela só deve ser executada na partida). Marcelo Ricardo Stemmer 199 .Informática Industrial I DAS/UFSC . bem como a quantidade total de carros no estacionamento. A entrada do estacionamento é controlada por uma sinaleira com uma lâmpada verde L1 e uma lâmpada vermelha L2. Uma segunda sinaleira indica se há vagas no térreo. bem como o número total de carros no estacionamento. a fotocélula FC4 é ativada e o número de carros do térreo bem como o número total de carros no estacionamento são decrementados em 1. Se um veículo do primeiro andar deseja sair do estacionamento. O esquema do estacionamento é apresentado na Figura 58. primeiro andar FC3 L6 L5 FC2 FC1 L4 L3 FC4 Saída Térreo Entrada L2 L1 Figura 58 . O acesso ao primeiro andar também é controlado por uma sinaleira com uma lâmpada verde L5 e uma lâmpada vermelha L6. A operação transcorre da seguinte forma: quando um veículo entra no estacionamento. As ligações de entrada e saída no CLP são indicadas na Figura 59. A tabela a seguir apresenta as entradas e saídas do CLP envolvidas nesta aplicação. elucidando suas funções.Esquema do estacionamento a ser controlado. Se houver vagas. Se um veículo sobe ao primeiro andar. a lâmpada vermelha L4 acende e o carro tem que se dirigir ao primeiro andar. que só permite a entrada de um carro caso haja ao menos uma vaga no estacionamento. com 10 vagas para carros em cada andar. A quantidade de carros em cada andar é controlada através das fotocélulas FC1 até FC4. a lâmpada vermelha L6 acende e a subida de novos veículos é impedida. O contador de carros pode ser resetado por meio do botão C0.Exemplo 2: Comando de um Estacionamento Um estacionamento é composto de 2 andares. a fotocélula FC1 é ativada e a quantidade de veículos no andar térreo é incrementada em 1. senão. a lâmpada verde L3 acende. a fotocélula FC2 é ativada e o número de veículos no térreo é decrementado em 1 enquanto o número de veículos no primeiro andar é incrementado em 1. Se um veículo estacionado no térreo deseja sair. Se o número de carros no primeiro andar chega a 10. a fotocélula FC3 é ativada e o número de carros no primeiro andar é novamente decrementado. Conexões de Entrada e Saída no CLP. o segundo conta os veículos no primeiro andar e o terceiro é um totalizador. Pav. Observe que aqui estamos usando bobinas simples. Pav. possibilidade de aproveitamento integral do raciocínio lógico utilizado na elaboração de um comando feito anteriormente com relês.7 • Vantagens e desvantagens da técnica As vantagens desta técnica de programação são: possibilidade de uma rápida adaptação do pessoal técnico. fácil recomposição do diagrama original a partir do programa de aplicação.. Sinaleira 1o. 1o. Verde Sinaleira 1o. 5. contando os veículos no estacionamento como um todo. permitindo depuração lógica e manutenção do software mais rápidas. Verde Sinaleira Térreo. • • • • • As vantagens citadas fazem desta técnica de programação a mais difundida e aceita a nível industrial atualmente. Verm. Verm. Fotocélula Saída. O programa em LD para o problema apresentado é mostrado na Figura 60. É provável que a tendência de introdução de disciplinas de programação de microprocessadores nos currículos das engenharias conduza a uma preferência futura por outras Marcelo Ricardo Stemmer 200 . Verde Sinaleira Entrada. Entrada / Saída E0 E1 E2 E3 E4 S0 S1 S2 S3 S4 S5 Ligação externa C0 FC1 FC2 FC3 FC4 L1 L2 L3 L4 L5 L6 Comentários Chave Resetar contador Fotocélula Entrada Fotocélula Subida Fotocélula Saída. Verm. representação dos símbolos do diagrama de escada padronizados de maneira idêntica nas normas NEMA ICS 3-304 e IEC 1131. fácil documentação.. Sinaleira Térreo.4. O primeiro deles conta os veículos no andar térreo.6. fácil visualização dos estados das variáveis sobre o diagrama de escada. mundialmente aceitas pelos fabricantes e usuários. Térreo Sinaleira Entrada. Observe que são utilizados aqui 3 contadores incrementais/decrementais.Informática Industrial I DAS/UFSC C0 FC1 FC2 FC3 FC4 E0 E1 E2 E3 E4 Entradas do CLP Saídas do CLP S0 S1 S2 S3 S4 +24V S5 L1 L2 L3 L4 L5 L6 Figura 59 . Pav. uma vez que a forma de descrição da lógica se assemelha muito aos diagramas elétricos convencionais e lógicas com relês. 5 Grafos de Comando Etapa-Transição (GRAFCET.5.6.Programa em LD para o estacionamento. SFC) 5. Programadores não familiarizados com a operação de relês tendem a ter dificuldades com esta linguagem. 5. Marcelo Ricardo Stemmer 201 . Esta linguagem também é conhecida como “Sequential Function Chart” (SFC).Informática Industrial I DAS/UFSC formas de programação. Paris). uma linguagem de mais alto nível do que as apresentadas anteriormente se faz necessária. A linguagem é uma adaptação da técnica de Redes de Petri e permite uma visualização dos estados pelos quais o sistema a comandar deve passar para realizar uma dada operação. E1 E0 = C0 E1 = FC1 E2 = FC2 E3 = FC3 E4 = FC4 I S3 S0 = L1 S1 = L2 S2 = L3 S3 = L4 S4 = L5 S5 = L6 E2 E4 D MAX = 10 E0 H S3 S2 E2 E3 I S5 D MAX = 10 E0 H S5 S4 E1 E3 E4 I S1 D MAX = 20 E0 H S1 S0 Figura 60 . O resultado de esforços neste sentido foi a definição da linguagem GRAFCET pela AFCET (Association Françoise pour la Cybernétique Economique e Technique.6.1 Introdução Para a programação de lógicas de comando mais complexas. Uma ação esta usualmente relacionada à ativação ou desativação de saídas do CLP.Etapas: correspondem a uma situação na qual o comportamento de todo ou parte do sistema é invariante em relação as suas entradas e saídas. à esquerda na Figura 61). descrita ao lado do símbolo da transição.6. .Ações: uma ação é sempre associada à uma etapa e só pode ser executada quando a etapa estiver ativada.Etapa (a) desativada. A transição é Marcelo Ricardo Stemmer 202 . . (b) incondicionais. (b) ativada. e a do GRAFCET normalizado (GN. Ações mais complexas podem se constituir de subrotinas completas. Sua representação é mostrada na Figura 62. O estado global de um sistema em um dado momento é dado pelo conjunto de etapas ativadas.5.2 Elementos básicos do GRAFCET Um grafo de comando etapa-transição é constituído dos seguintes elementos: . Ações simples.Informática Industrial I DAS/UFSC 5. (GO) Se porta aberta: acender lampada a) (GN) b) Acender lampada Figura 62 . podem ser implementadas diretamente no grafo. A representação gráfica da ficha é feita por meio de um ponto (Figura 61. semelhante a adotada em redes de Petri. Duas representações são utilizadas para as etapas: a do GRAFCET original (GO. Uma etapa pode estar ativada ou desativada em um dado momento. como IL ou LD. A cada transição é associada uma condição lógica chamada receptividade.Ações (a) condicionais. cuja representação gráfica no computador é mais fácil.Transições: indicam a possibilidade de evolução entre etapas. as etapas representam um estado parcial do sistema. Assim. O conjunto de etapas ativadas constitui a "marcagem" do grafo. A execução de uma ação pode estar condicionada a uma função lógica de variáveis de entrada do CLP ou ao estado ativo ou inativo de outras etapas. à direita na Figura 61). a) (GO) (GN) b) (GO) (GN) Figura 61 .b). Representa-se a ativação de uma etapa colocando uma ficha ("token") em seu interior. que podem inclusive ser implementadas em outras linguagens. como ativar ou desativar uma saída. conforme a Figura 63.C2) Figura 63 . Marcelo Ricardo Stemmer 203 . A receptividade em geral é uma função associada ao estado das entradas do CLP.Exemplo de receptividade tempo. 6 t/6/10s T3 7 Figura 65 .Informática Industrial I DAS/UFSC representada graficamente por uma barra com a receptividade indicada ao lado desta. Neste caso. Um exemplo deste tipo de receptividade é apresentado na Figura 65. a representação é mostrada na Figura 64. Contato C1 fechado (C1) Contato C1 fechado e C2 aberto (C1. En t/<etapa origem>/<tempo> Tn En+1 Figura 64 .Receptividade tempo.Transições e suas receptividades. Uma receptividade especial é a que manipula a variável tempo. Informática Industrial I DAS/UFSC Caso não haja condição associada a receptividade, esta é chamada de "receptividade incondicional", que é representada conforme a Figura 66. =1 Figura 66 - Receptividade incondicional. - Arcos: ligam sempre uma transição à uma etapa ou uma etapa à uma transição. Sua representação gráfica é mostrada na Figura 67. Os arcos podem ser de entrada ou de saída, isto é, arcos que entram ou saem de etapas (Figura 68) ou de transições. Etapa arco Trans. arco Figura 67 - Arcos (GO). arcos de entrada (GO) (GN) arcos de saida Figura 68 - Arcos de entrada e saída. 5.6.5.3 Regras de Evolução do GRAFCET Cinco regras definem a evolução do estado (ou marcagem) do GRAFCET: Marcelo Ricardo Stemmer 204 Informática Industrial I DAS/UFSC - Regra 1: As etapas ativadas na condição inicial devem ser assinaladas com um duplo circulo (GO) ou duplo quadrado (GN), conforme mostra a Figura 69. As etapas usualmente são numeradas a partir daquela que representa a condição inicial (que recebe o número 1). 1 (GO) 1 (GN) Figura 69 - Condição inicial do grafo. - Regra 2: Uma transição será válida se todas as etapas de entrada desta estiverem ativadas. Se a transição é válida e a receptividade a ela associada é verdadeira, a transição é dita disparável. O "disparo" (definido a seguir), nestas circunstâncias, é obrigatório. - Regra 3: "Disparar" uma transição consiste em ativar todas as etapas de saída da transição e desativar todas as etapas de entrada (Figura 70 e Figura 71). a) b) Figura 70 - Disparo simples (a) antes; (b) depois. a) b) Figura 71 - Disparo múltiplo (a) antes; (b) depois. Marcelo Ricardo Stemmer 205 Informática Industrial I DAS/UFSC - Regra 4: Várias transições simultaneamente disparáveis no grafo deverão ser efetivamente disparadas no mesmo instante. - Regra 5: Se uma etapa deve ser desativada e ativada simultaneamente, ela permanece ativada (Figura 72). Figura 72 - Etapa com realimentação. 5.6.5.4 Estruturas lógicas em GRAFCET Diversas estruturas lógicas complexas podem ser representadas em GRAFCET, conforme mostrado a seguir. Uma estrutura lógica "OU" pode aparecer sob a forma de uma divergência (Figura 73), correspondendo a uma estrutura de software do tipo: "SE (estado = x E C1 verdadeira) ENTÃO (passe ao estado y) SENÃO SE (estado = x E C2 verdadeira) ENTÃO (passe ao estado z)". (GO) (GN) C1 C2 C1 b) C2 a) Figura 73 - Divergência em OU (a) GO; (b) GN. Uma convergência em "OU" (Figura 74) corresponde, por sua vez, a uma estrutura de software do tipo: "SE (estado = x E C1 verdadeira) OU (estado = y E C2 verdadeira) ENTÃO (passe ao estado z)". Marcelo Ricardo Stemmer 206 Informática Industrial I DAS/UFSC C1 C1 C2 C2 (GO) (GN) a) b) Figura 74 - Convergência em OU (a) GO; (b) GN. Uma divergência em "E" (Figura 75) eqüivale a uma estrutura de software do tipo: "SE (estado = x E C1 verdadeira) ENTÃO (passe aos estados y E z)". C1 (GO) C1 (GN) a) b) Figura 75 - Divergência em E (a) GO; (b) GN. Finalmente, uma convergência em "E" (Figura 76) eqüivale a estrutura: "SE ((estado = x E y) E (C1 verdadeira)) ENTÃO (passe ao estado z)". Marcelo Ricardo Stemmer 207 Isto eqüivale a dizer que não podem haver ramos do grafo por onde a ficha jamais passa. • Grafo Determinísta: um grafo é dito determinista quando todos os possíveis conflitos nele contidos estão resolvidos de forma inequívoca. 5. • Grafo Reinicializável: quando. Se este limite é “1”.6. para qualquer marcagem acessível M e qualquer transição T. Um estudo mais detalhado do assunto pode ser encontrado na vasta literatura disponível sobre Redes de Petri. Marcelo Ricardo Stemmer 208 . o grafo é dito seguro. (b) GN. de onde esta técnica de programação é derivada. existe uma seqüência de tiro disparável a partir de M que inclua T. • Grafo Vivo: quando. o grafo é dito vivo.5.Convergência em E (a) GO. O que veremos a seguir é apenas uma breve introdução ao aspecto de análise e validação do GRAFCET. Um grafo correto em GRAFCET deve possuir as seguintes 5 propriedades: • Grafo Limitado e Seguro: quando o número de fichas contido em qualquer etapa é inferior a um dado limite para qualquer marcagem possível. baseada em certas propriedades básicas que um grafo correto deve apresentar. o grafo é dito reinicializável. Uma etapa onde possam se acumular fichas em número ilimitado é indicativo de um erro de especificação.Informática Industrial I DAS/UFSC C1 (GO) C1 (GN) a) b) Figura 76 . Duas transições são ditas em conflito se existe uma marcagem acessível que sensibilize as duas ao mesmo tempo. o grafo é dito limitado. de forma que o disparo de uma delas impeça o da outra. para qualquer marcagem acessível atingida a partir da marcagem inicial. existe uma seqüência de disparo que permita o retorno a marcagem inicial. como na Figura 77.5 Análise e validação do GRAFCET Um dos aspectos mais interessantes desta linguagem de programação para CLP é a possibilidade oferecida por ela de realizar uma verificação de correção lógica das especificações. A B Figura 79 – Etapas A e B em Paralelo Marcelo Ricardo Stemmer 209 . Um conflito é dito resolvido se as etiquetas associadas às transições envolvidas não permitam nunca o valor “verdade” para as duas simultaneamente. como ilustrado na Figura 78. ] [C1. Ação1 Ação2 Figura 78 – Conflito resolvido (estrutura tipo IF . como mostrado na Figura 79.ELSE). ] IF (C1=TRUE) THEN Ação1 ELSE Ação2.THEN . Duas etapas são ditas paralelas se existe uma marcagem acessível que ative as duas mesmo tempo. [C1.Informática Industrial I DAS/UFSC A B Figura 77 – Transições A e B em Conflito. • Grafo Determinado: um grafo é dito determinado se só há ações que possam ser executadas simultaneamente associadas a etapas paralelas. o que no caso geraria um erro (leitura e escrita simultâneas de uma mesma área de memória). Enquanto um pallet é carregado no AGV no porto A. O AGV deve transportar pallets do porto A ao porto B. nada impede que as duas ações sejam executadas ao mesmo tempo. um robô remove o pallet anterior do porto B (caso haja algum). Isto corresponde a uma situação típica de automação onde um intertravamento se faz necessário. foi elaborada para redes de Petri e não especificamente para GRAFCET.Informática Industrial I DAS/UFSC O grafo da Figura 80. facilitando enormemente a tarefa de validação de software. C1 C1 [escrever x] [lêr x] [escrever x] [lêr x] a) b) Figura 80 – (a) Grafo não Determinado. A maioria destas ferramentas. Em uma das etapas definiu-se a ação de ler o valor de uma variável x. Hoje já estão disponíveis programas de computador capazes de realizar automaticamente uma verificação de algumas destas propriedades.a exemplifica uma situação em que são associadas ações incompatíveis entre si a etapas paralelas.6 Exemplo de programação em GRAFCET Deseja-se realizar o comando de um sistema de transporte de peças em Pallets que inclui um AGV (Automatic Guided Vehicle). caso qualquer uma das cinco propriedades básicas acima esteja faltando. conforme mostrado na Figura 81. Marcelo Ricardo Stemmer 210 . é de se supor que ocorreu um erro sério de especificação e o programa deve ser revisto. 5. como ilustrado na Figura 80.5.6. no entanto.b. enquanto na outra definiu-se a ação de escrever um novo valor para a mesma variável. (b) Grafo determinado via intertravamento. Na análise do GRAFCET. Como as duas etapas podem ser ativadas simultaneamente. Marcelo Ricardo Stemmer 211 .CP = Carrega Pallet no AGV .B = AGV no porto B Sinais de Saída: (Atuadores) .PA = Pallet em A .E = AGV se desloca para a Esquerda .DP = Descarrega Pallet do AGV .PB = Pallet em B .S = AGV parado (Stop) .RP = Remove Pallet (Robô) O GRAFCET que realiza o comando pretendido é representado na Figura 82.Informática Industrial I DAS/UFSC FMC Correia Entrada Robo PB Correia Saida Pallet PA AGV FC A B Porto A Porto B Figura 81 .A = AGV no porto A .FC = Fim de carregamento do Pallet no AGV .D = AGV se desloca para a Direita .Sistema de transporte com AGV. A operação é comandada por um CLP através dos seguintes sinais de entrada e saída: Sinais de Entrada: (Sensores) . R P .D 7 =1 RP 8 PB DP 9 E . abrangência.GRAFCET (GN) para o comando do sistema de transporte.6. formalização rigorosa. permitindo análise e documentação precisas.7 Normas Relevantes Para CLPs Diversas entidades internacionais preocupam-se com a criação e o aperfeiçoamento de normas específicas sobre CLPs. O GRAFCET pode ser programado com o auxílio de recursos gráfico-interativos ou por meio de uma linguagem textual que descreva o grafo. 5.Informática Industrial I DAS/UFSC 1 PA S . facilidade de decomposição do sistema em subsistemas funcionais. Algumas normas que merecem atenção são listadas a seguir [3]: • NEMA (National Electrical Manufacturers Association) ICS 1-109 "tests and test procedures": define uma série de testes aplicáveis a nível de projeto. podendo representar a maioria dos sistemas de controle lógico industriais.5. NEMA ICS 2-230 "Components for solid-state logic systems": descreve testes e equipamentos para verificação de imunidade a ruído. 212 • Marcelo Ricardo Stemmer .E 2 FC CP 4 3 A B PB D 6 CP PB RP PB 5 S . produção e aplicação de CLPs. capacidade de uso em vários níveis de interpretação.7 Vantagens da técnica As principais vantagens do uso do GRAFCET são: • • • • • • simplicidade de interpretação. facilidade de representação de sistemas com paralelismos. 5. S Figura 82 .D P . dentro dos quais os CLPs devem funcionar sem apresentar defeitos. OR. LD. ISA-SP50. da lógica digital em programa de CLP).). usinas elétricas. Aqui.Informática Industrial I DAS/UFSC • • IEEE std 518-1977 "Guide for installation of electrical equipment to minimize electrical noise inputs to controllers from external sources": contém um estudo sistemático sobre ruídos. CAN. LON. recuperação de falhas. estabelecem parâmetros máximos e mínimos de operação. em vista da tendência de integração total de todos os níveis hierárquicos de automação verificada após a introdução da filosofia CIM (Computer Integrated Manufacturing). ST (Structured Text. A tendência dominante. um computador ligado à rede toma as decisões centrais e vários CLPs ligados a ele via rede interagem com o ambiente a ser controlado e supervisionado por meio de seus módulos de entrada e saída (Figura 84). Outra importante aplicação de módulos de rede para CLP é a interligação destes com Sistemas Supervisórios. Entre as redes mais difundidas a este nível hierárquico de automação estão os sistemas BITBUS. Exemplos de tais programas Marcelo Ricardo Stemmer 213 . tais como refinarias. redundância. só para citar alguns poucos exemplos. Diversos fabricantes de componentes para automação industrial. INTERBUS-S.CLP com módulo para interligação em rede. é a de procurar seguir um dos vários sistemas atualmente propostos para padronização de redes para chão de fábrica (FIP. 5. semelhante a Pascal) e FBD (Functional Block Diagram. SERCOS. A norma IEC 1131 padroniza 5 linguagens para CLP: IL. PROFIBUS. Figura 83 . FIP. Muitos fabricantes oferecem redes "proprietárias" para esta finalidade (redes com tecnologia própria). abordando problemas de confiabilidade. sistemas de comunicação. entre outros. etc. etc. TOKEN-RING e ETHERNET. etc. plantas químicas.8 Interligação de CLPs Utilizando Redes de Comunicação A padronização dos canais de comunicação entre CLPs e outros equipamentos inteligentes de automação tem adquirido grande importância. que rodam em computadores tipo PC e permitem visualizar na tela do mesmo o andamento do processo sendo controlado pelo CLP. usado para o controle e supervisão de sistemas complexos envolvendo grande número de grandezas. e descrevem testes padronizados para caracterizar e verificar as especificações dos fabricantes. Uma das possíveis áreas de aplicação de CLPs interligados por uma rede de comunicação é a realização de um SDCD (Sistema Digital de Controle Distribuído). XOR. tipos de programação e subsistemas para CLPs. NEMA ICS 3-304 e IEC 1131: são as normas mais completas sobre CLPs. suas fontes e métodos de redução. que transforma um desenho de um diagrama de blocos com portas AND. Elas enumeram estruturas. incluindo a maioria dos CLPs. no entanto. já fornecem interfaces para rede em seus produtos (Figura 83). GRAFCET. PROFIBUS. mas deverá passar por um processo de padronização em breve (a IEC já está realizando estudos neste sentido).44% dos CLPs instalados são de pequeno porte.9 O Mercado de CLPs no Brasil No Brasil.579 em 1992. 5.75% são de grande porte.5 milhões de dólares em 1992 (Figura 85). Os restantes 7. automação predial e controle de subestações de energia. Elipse 21. 44. Enquanto alguns fabricantes desenvolveram tecnologia própria. Com relação as aplicações mais comuns. grande parte deles adota tecnologia importada. com as mais variadas especificações. O mercado de CLPs no Brasil. linhas de fabricação de máquinas.00% na área de manufatura.. 40. apesar de enfrentar uma queda no volume de vendas nos anos de 1990 e 1991.70% dos CLPs usados são de fabricação nacional.14% das empresas usuárias de componentes para automação industrial utilizam CLPs. Unisoft.40% são de médio porte e 19. o estudo mostra que 42.8 milhões de dólares em 1986 para 61. laboratórios de teste. passou-se de um volume de vendas de 27. O número de unidades vendidas cresceu de 3. CLP1 CLP2 CLPn Figura 84 . 28.41% dos usuários não respondeu a pergunta.Informática Industrial I DAS/UFSC supervisórios são o FIX (versões SCADA e MMI). O mesmo estudo indica ainda que 69. Genesis. Os fabricantes atuais de CLP oferecem algumas instruções adicionais para permitir o desenvolvimento de programas aplicativos que façam uso do acesso a rede. Segundo um estudo publicado pela SOBRACON [11]. As instruções mais usuais são as de leitura e escrita de operandos em outros CLPs conectados à rede.67% dos CLPs instalados são usados na área de controle de processos. mais de 20 empresas estão produzindo CLPs. Além disso.68% na integração de sistemas de automatização industrial. Algumas características básicas de produtos dos principais fabricantes são mostradas na tabela a seguir [1]. indicando uma boa recuperação do setor após a crise de 1990/91. vem apresentando desde então um franco crescimento.00% são usados em ensino e 2..SDCD com CLPs interligados via rede. Rede de comunicação Módulo de Interface para rede . entre outros.324 em 1990 para 5. A maioria dos fabricantes de CLP oferece drives específicos de seu produto para estes softwares. 48. A sintaxe de tais comandos ainda varia de fabricante para fabricante. 4. InTouch. Marcelo Ricardo Stemmer 214 . Os restantes são aplicados em áreas diversas como controle de demanda. Informática Industrial I 70 DAS/UFSC F a t u r a m e n t o 60 50 40 30 20 10 0 1986 1987 1988 1989 1990 1991 1992 U$ milhões ANO Figura 85 . 8040 8040 8035 8031 80C32 ALTUS (Bosch) BCM Cambridge Chronos Contrap CGR Digicon 16K 16 16 Engeletro FANUC (GE) Geotron Herge Italvolt Siemens Allen-Bradley Pulse 12 256 256 4 320 512 8 256 256 4 320 512 220 256 4096 40 512 512 512 32K 8K 16K 2K 4K 8K 3K 8K 16K 14K 3K Z80-2 8085 8085 80188 80188 8085 8085 8748 512 512 128 Möller SCI Villares WEG (AEG) 8 8 8 8 8 256 12 12 8 8 8 8 8 256 12 12 128 896 16 40 80 288 256 512 4096 336 336 1K 8K 4K 4K 4K 4K 12K 1K 8K 8K 8080A 8086 Marcelo Ricardo Stemmer 215 . Proc. Fabricante ATOS Modelo (exemplos) MPC-504 MPC-514 MPC-264 AL-1000 AL-600 CAMCON-80 CAMCON-100 CPC-1000 CA-1200 MPI-256 MPI-4096 D-20 CP/DIG-80 CP/DIG-80-10 1484 PLC90-30 modelo 311 PLC90-30 modelo 331 Geotron CLP HSC-1000 MPC-85 MPC-130 Simatic S5 Simatic S7 CLP2mini CLP2/20 CLP-16 CLP-40 CLP-80 PS-22 CP-80 Vilogic-500 CPW-A500 CPW-A200 CPW-A100 E 20 32 16 32 16 26 S 12 16 16 32 8 20 Max E+S 32 48 128 256 256 256 Mem.Faturamento do setor de CLPs no Brasil (1986-1992). Modernos sistemas de sensoreamento inteligentes permitem uma configuração flexível. A complexidade requerida de um sensor depende da tarefa a que está destinado. temos: • • • • • • • aquisição de dados utilizando transdutores já disponíveis digitalização e codificação dos dados filtragem digital de sinais compactação de informações e eliminação de redundâncias calibração do sensor supervisão de valores limite correção automática de erros sistemáticos (não linearidade. Potência Rotação Força Pressão Temperatura . etc... de peças Identificação de ferramentas Figura 86 ..Grandezas a medir na automação. Uma opção em estudos é a introdução de um “sistema operacional” para sensores. que podem ou não ser utilizadas em um dado sensor.) A programação destas funções no sensor inteligente pode ser feita por meio de gravação de uma EPROM ou através de carregamento de programa (downloading) via interface de comunicação.Informática Industrial I DAS/UFSC 6 Sensores e Atuadores Inteligentes A introdução de µp e µc em sistemas de sensoreamento a atuação tornou possível a realização de uma série de funções de forma distribuída..1 Sensores Inteligentes As principais tarefas executadas por sensores nos diversos setores industriais estão representadas de forma genérica na Figura 86. desvio padrão. Entre as possíveis funções a serem realizadas por sensores inteligentes. Um tal sistema operacional teria as seguintes funções básicas: Marcelo Ricardo Stemmer 216 .. Força Dilatação Estrutura .. • cálculo de grandezas derivadas do valor medido (valor médio. dependências de temperatura (“Drift”).. Tarefas de sensores na Produção Aquisição de dados de estado Posição Angulo Força Rotação Torque Dilatação Pressão Temperatura Corrente .. etc. Forma Côr Código Massa Dimens. Verificação da Geometria Verificação da função controle de sistemas supervisão de sistemas Verificação do material Aquisição de dados de qualidade Comprimento Angulo Diametro Superficie Forma . ... que inclui uma série de funções padronizadas. 6. Tais funções eram realizadas anteriormente em uma unidade central de processamento. Contador Força Pressão . Marcelo Ricardo Stemmer 217 .. Adaptação à periferia Fim-de-curso botoeira . • comunicação com o mundo exterior: interface para rede com protocolo de comunicação padronizado (rede tipo “FieldBus”) Apesar da grande variedade de transdutores existentes. relês. chaves fim-de-curso. Temperatura entradas analógicas (MUX) ROM RAM entradas digitais CPU Sensor virtual DPRAM coproc. conversão de formato.) • entradas analógicas: 0-20mA. 0-12V.. conversores..2 Atuadores Inteligentes Atuadores convertem sinais elétricos de corrente ou tensão em outras grandezas físicas como: • • • • • velocidade força pressão rotação/translação temperatura. 0 a 10V. ±10V (usando conversores analógico/digital) A configuração básica de um sensor inteligente é mostrada na Figura 87. 6. etc. • administração e processamento de dados: armazenamento local.. temporização.. 4-20mA.Informática Industrial I DAS/UFSC • controle de hardware: comando das entradas. botoeiras. etc. a maioria destes converte a grandeza física medida em um dos seguintes sinais elétricos: • entradas binárias ou digitais: TTL. acesso às funções de uma biblioteca.. etc. etc. 0-24V (encoders..Configuração básica de um Sensor inteligente. 0 a 5V. comunicação (Layer 2) Interface serial BUS Figura 87 .. ±5V. Informática Industrial I DAS/UFSC Os sinais convertidos são utilizados para afetar o comportamento de um dado sistema. Reles adaptação à periferia saídas digitais Atuador virtual Motor DC saídas analógicas Servoválvula Motor AC e de passo ROM RAM CPU DPRAM coprocessador comunicação (Layer 2) interface serial BUS PWM Figura 88 . Marcelo Ricardo Stemmer 218 . 4-20mA. motores de passo. 0 a 5V.) • saídas PWM (Pulse Width Modulation): motores AC. ±5V. motores DC.) • saídas analógicas: 0-20mA. 0 a 10V. etc. etc. etc. 0-12V. 0-24V (relês. ±10V (servo-válvulas. A configuração básica é semelhante a de um sensor inteligente (Figura 88). como: • aumentar ou diminuir a vazão num cano • aumentar ou diminuir a temperatura em um forno industrial • aumentar ou diminuir a velocidade de avanço ou de corte de uma máquina-ferramenta A maioria dos atuadores podem ser comandados com um dos seguintes sinais elétricos: • saídas digitais: TTL.Configuração básica de um Atuador Inteligente. Trabalho 2 A decomposição LDU é uma decomposição famosa de matrizes aplicada para calcular inversas de matrizes e resolver problemas de equações lineares. Utilize uma classe para os clientes e outra para as fitas. com pivotamento. O usuário de poder incluir/retirar um cliente ou uma fita. a ser proposto pelos alunos e apresentado ao professor (em equipe). Marcelo Ricardo Stemmer 219 . pedir a lista de clientes e a lista de fitas ou alterar algum parâmetro destas. Trabalho 3 Crie um programa que faça o controle de cadastro de usuários e controle de alocação para uma locadora de fitas de vídeo. preferencialmente.1 e crie um programa que calcule a decomposição LDU de uma matriz. fazer uma pesquisa. Trabalho 4 Tema livre.Informática Industrial I DAS/UFSC 7 Anexo I – Trabalhos em C/C++ Trabalho 1 Crie um programa que desenhe na tela o seu quadro de horários deste semestre. Utilize o programa 9. e empregue o método da lista ligada para gerenciar um vetor dinâmico. As ligações no CLP são apresentadas na Figura 90. a lâmpada H0 acende. Botão de Partida C0 Lâmpada de operação H0 Botão de Emergência C6 Misturador M1 com sensor F1 Bomba M2 com sensor F2 Válvula Y1 Válvula Y2 sensor nível B4 sensor nível B2 sensor nível B1 Tinta 1 Tinta 2 hélice do misturador Figura 89 . ou pelo sensor B4. usando Diagramas de Escada. A Figura 89 apresenta o esquema do misturador. a bomba M2 é desligada e o misturador M1 é ativado. respectivamente.Misturador de Tintas (2 côres). A tabela a seguir mostra os sinais de entrada e saída utilizados e descreve seu uso nesta aplicação. a válvula Y1 é fechada e a válvula Y2 é aberta. indicando inicio de operação. que indica enchimento total do recipiente de mistura. O misturador pode ser desligado em qualquer ponto da operação por meio do botão de parada de emergência C6. pelos sensores térmicos F1 ou F2 ligados aos motores do misturador e da bomba. Quando o nível total de tinta atinge o sensor B2.Informática Industrial I DAS/UFSC 8 Anexo II – Trabalho de CLP MISTURADOR AUTOMÁTICO DE TINTAS Um misturador automático para duas côres de tintas deve ser comandado por meio de um CLP. a válvula Y1 abre e a bomba M2 é ligada. Elabore o programa de comando do misturador no CLP. misturando a segunda tinta ao conteúdo do recipiente. a válvula Y2 é fechada. Marcelo Ricardo Stemmer 220 . Após 6 segundos o misturador M1 e a lâmpada H0 são desligados e a tinta já homogeneizada pode ser removida (manualmente). A operação transcorre da seguinte forma: após pressionar o botão de partida C0 (botoeira que mantém contato somente enquanto pressionada). Quando o nível da primeira tinta no recipiente de mistura atinge o sensor B1. Informática Industrial I DAS/UFSC C0 B1 B2 B4 C6 F1 F2 E0 E1 E2 E3 E4 E5 E6 Entradas do CLP +24V Saídas do CLP S0 S1 S2 S3 S4 H0 Y1 Y2 M1 M2 Figura 90 .Conexões de Entrada e Saída no CLP Entrada / Saída E0 E1 E2 E3 E4 E5 E6 S0 S1 S2 S3 S4 Ligação externa C0 B1 B2 B4 C6 F1 F2 H0 Y1 Y2 M1 M2 Comentários Chave Partida Sensor de nível Sensor de nível Sensor de nível Chave Parada Emergência Sensor térmico Misturador Sensor térmico Bomba Lâmpada de operação Válvula tinta 1 Válvula tinta 2 Motor Misturador Motor Bomba Marcelo Ricardo Stemmer 221 . Moscato. Foot Filho. Düsseldorf. [2] Lócio e Silva. W.1 CLP [1] Stemmer. : "Werkzeugmaschinen". Del Bianco F. [3] Gerbase. Cirelli. : "Controlador Programável". [9] Berger. A.P. [7] Blanchard. Bolton : “Programmable Logic Controllers : An Introduction “. [5] Rillo. [8] De Oliveira. D. Jeffcoat : “The Plc Workbook : Programmable Logic Controllers Made Easy”. 1985. Alemanha.. : "Tendências atuais na normalização de controladores lógicos programáveis". : "Equipamentos de automatização da manufatura".R. Prentice-Hall.. 1985. 1999. [15] Mandado. Prentice Hall . H. Anais do II CONAI. Siemens AG. Zilinskas. : "Controladores lógicos programáveis: aplicações na manufatura". Anais do VI Seminário de Comando Numérico no Brasil. Cepadues Editions. L.. Clements-Jewery. L. 1985. Enrique : “Programmable Logic Devices and Logic Controllers”. [4] Cugnasca. John et all: “Programmable Logic Controllers: Principles and Applications”. Prentice-Hall. 1979.. [13] Peter Rohner : “Automation With Programmable Logic Controllers”. J. 1998. C. 1986. M. M. 4th edition. J. Alemanha. : "Comprendre maitriser et appliquer le GRAFCET". Berlin e Munique. MacMillan. [6] Weck. Makron-Books do Brasil Editora. Jon : “Fundamentals of Programmable Logic Controllers. Anais do II CONAI.: "Controlador programável por grafos de comando etapa-transição (GRAFCET)". : "Programmieren von Funktionsbausteinen in STEP5". H. 1986.. [17] W.. O. S. Anais do II CONAI. VDI-Verlag. Band 3. [16] K. São Paulo. 1989. E. 1993. W.J.Informática Industrial I DAS/UFSC 9 Bibliografia 9. 1996. Marcelo Ricardo Stemmer 222 . [11] Webb. França. 1985. Toulouse. [14] Simpson. Sensors and Communications”. Colin : “Programmable Logic Controllers”.H. C. 2nd edition.E.A : "Métodos de programação de controladores lógicos programáveis". [12] Stenerson. [10] SOBRACON : "Guia Brasileiro de Automatização Industrial 1992".. Prentice Hall .C. Anais do II CONAI. Costa Rillo. F. P. 1994. B.: “The Unified Modelling Language – User Guide”. Ed. Programmierung. Ciência Moderna. [8] Mizrahi. [13] Stevens. Victorine Viviane. M.. I. Borland International.Módulo 1 e 2”. [7] Meyer. Pacheco. George Leinonen : “Programmable Controllers and Designing Sequential Logic”. Borland International. I. Roberto: “Orientação a Objetos em C++”. Premerlan. 1999. Ed. R. F. Washington.: “The Unified Software Development Process”. [6] Mizrahi. e Lorensen. Marcelo Ricardo Stemmer 223 .: Eddy. Sams Publishing. Saunders College Publishing Series in Electronics Technology. São Paulo. Addison Wesley Longman.1990. [5] Douglass. J. 9. [10] Petzold. Makron Books do Brasil. [11] Reidorph. Addison Wesley Longman. 1992. [19] George L.: “Treinamento em Linguagem C++ . ed.: “Real-Time UML : Developing Efficient Objects for Embedded Systems”. Ed. Ed.: “Object-Oriented Software Construction”. Berkeley Brasil. Tom: “Programação Avançada em Borland C++ 4 Para Windows”. Makron Books do Brasil. Bertrand . Filer. USA. J. Blaha. Victorine Viviane. 1996. e Rumbaugh. and Applications”. Software. Kent: “Teach Yourself Borland C++ Builder 3 in 21 Days”. Addison Wesley-Logman. Hanser and Ed. Microsoft Press. [14] Swan. Jacobson. [9] Montenegro. Rio de Janeiro. Módulo 1. Indianapolis. G. USA. Fernando.. São Paulo. e Rumbaugh. Ed. W. São Paulo. 1994. August of 1998. Prentice-Hall. George J. Petruzella: “Programmable Logic Controllers”.: “Treinamento em Linguagem C – Curso Completo”.Informática Industrial I DAS/UFSC [18] Robert F. Jacobson.2 C/C++ [1] Booch. W.. 1994. Prentice Hall. 1994. Ed.. Anwendung“. 1998. G. 1994.: “Object-Oriented Modelling and Design” .. Ed. [4] Borland C++: “User’s Guide”. [12] Rumbaugh. [2] Booch. Jr. W. [3] Borland C++: “Programmer’s Guide”. ed. Batten : “Programmable Controllers : Hardware. USA.. Ed.: ”Programmieren von Unix-Netzen – Grundlagen. J. Prentice Hall. January of 1999. Batten. [20] Frank D. Charles: “Programming Windows 95”. geog.uk/staff/i.isg.com/services/enterprise/uml/uml.borland.leeds.turton/unix/course.com/uml/ http://www.edu/resource/docs/linux/LDP/lpg/node1.com http://www.com/ http://msdn.com/resources/devcenters.uk/staff/i.togethersoft.ac.popkin.de/world/ http://www.com/together/togetherC.3 Hot Sites • • • • • • • • • • • http://www.html Marcelo Ricardo Stemmer 224 .html http://world.ee.microsoft.microsoft.rational.htm http://www.asp http://search.com/us/dev/ http://www.cooper.developer.html http://www.ac.geog.leeds.turton/unix/course.html http://www.Informática Industrial I DAS/UFSC 9.