Você está na página 1de 815
2 Cc Completo e Total 3a Edicao Revista e Atualizada Herbert Schildt Traducao e Revisto Técnica Roberto Carlos Mayer Diretor da Mayer & Bunge Informética Prof. do Departamento de Cigncia da Computagao da USP-SP MAKRON Books Ltda. Rua Tabapua, 1.348 — Itaim-Bibi 747 — Lapa (CEP 04533-004 — Sao Paulo — SP CEP 05065-110— Sao Paulo — SP (11) 3849-8604 e (11) 3845-6622 (11) 3611-0740 e-mail: makron@books.com.br fax (11) 3611-0444 Siio Paulo + Rio de Janeiro * Ribeirdo Preto + Belém * Belo Horizonte + Brasilia * Campo Grande Cuiabéi + Curitiba + Floriandpolis + Fortaleca * Goidnia * Manaus + Porto Alegre + Recife + Salvador Brasil » Argentina * Colmbia * Costa Rica * Chile * Espanha * Guatemala + México * Pere + Porto Rico * Venezuela Do original C: The Complete Reference — Third Edition Copyright © 1995 McGraw-Hill, Inc Copyright © 1987 Makron Books do Brasil Editora Ltda. Todos os direitos para a lingua portuguesa reservados pela Bditora McGraw-Hill, Ltda, e Makron Books do Brasil Editora Lida. Nenhuma parte desta publicagie podera ser reproduzida, guardada pelo sistema “retrieval” ou transmitida de qualquer modo ou por qualquer outro meio, seja este eletrOnico, mecinico, de fotocépia, de gravagio, ou outros, sem prévia autorizacio, por escrito, das Editoras. EDITOR: MILTON MIRA DE ASSUMPGAO FILHO Produtora Editorial: Joana Figueiredo Produtor Gréfico: José Roberto Petroni Editoragao Eletronica: E.R.J. Informatica Ltda Dados de Catalogagao na Publicagao (CIP) Internacional (Camara Brasileira do Livro, SP, Brasil) Schildt, Herbert C, completo e total - 3! edicgdo revista e atualizada Herbert Schildt ; tradugdéo e revisdéo técnica Roberto Carlos Mayer. Sao Paulo : Makron Books, 1996. rence Titulo original: C: the complete re ISBN 85-346-0595-5 1. C (Linguagem de programagdéo) I. 6-0491 CDD-005.133 indices para catalogo sistematic 1. C : Linguagem de programacdo : Computadores Processamento de dados 005.133 Sumario © Que Ha de Novo Nesta Edicéo Dn XXIV O Que Ha n0 LivIO eccecetesstevtevssevesevestsesess : XXV Parte 1 — A Linguagem C0... 0s. eeeseeeeee sence tence eeeeneaneaee 1 1, Uma Visdo Geral de Co... ce seseeees sence ceca eeeee eens aeeree 3 As Origens de C 3 C E uma Linguagem de Médio Nivel . 5 4 CE uma Linguagem Estruturada ..... venteeeee cee 5 C E uma Linguagem para Programadores 7 Compiladores Versus Interpretadores . . 9 A Forma de um Programa em C ..... sete cee A Biblioteca ea Linkedigado .......... 000000 esceee eer 1 Compilagdo Separada ... 0.6... 06 00sec eve eee eeeeee eee cee 212 Compilando um Programa em C ..... 6.6... 000 eee eeeeeeeeeees se © Mapa de Memoria de C 13 C Versus C++ .. bebe tee et een teeeeee 14 Um Compilador C++ Funcionaré com Programas C? ...... cece D5 Uma Revisdo de Termos eee a eee 2. Expresses EMC... 0... e cece eee cece tenet eee e eee eee ee eee 16 Os Cinco Tipos Basicos de Dados 16 Modificando os Tipos Basicos .. 17 Nomes de Identificadores . 19 Varidveis 0.0000 c ce eeeee cece eeeeee : eo 20 VI C= Completo ¢ Total Onde as Varidveis Sao Declaradas Varidveis Locais Parametros Formais Variaveis Globais ... Modificadores de Tipo de Acesso const . 20 voiatile dores de Tipo de Classe de Armazenamento A Varidveis static : 7 Variaveis register Inicializagao de Variaveis Constantes . . Constantes Hexadecimais e Octais Constantes String Constantes Caractere de Barra Invertida Operadores . O Operador de Atribuicao Conversio de Tipos em Atribuigoes: Atribuigdes Multiplas . Operadores Aritméticos Incremento e Decremento . Operadores Relacionais e Logicos Operadores Bit a Bit O Operador ? .... 5 Os Operadores de Ponteiros & e* .... O Operador em Tempo de Compitacio s O Operador Virgula ... : Os Operadores Ponto () e Seta (>) Parénteses e Colchetes Como Operadores Resumo das Precedéncias Expressdes Ordem de Avaliagao : Conversio de Tipos em Expresses. Casts Espagamento e Parénteses C Reduzido izeof . Comandos de Controle do Programa . Verdadeiro e Falso em C bev eeveeeeseeceeeteevevtreeeees Comandos de Selegio beeteteenee if ifs Aninhados beeecens A Escada if-else-if .... feveeens O? Alternativo. . Sumo vil A Expresso Condicional ...... vec eeeteeeeettte ete t ttt e eee es 69 switch es 70 Comandos switch Aninhados ........0cc0s 0s veceeeeees 74 Comandos de Iteragdo . feetteeeees coven 74 O Lago for eee cece beeen voveeetnee 74, Variacées do Lago for .. teens ee .-76 O Lago Infinito 2... eee cece eee peer - 80 Lagos for sem Corpos pee neneeernrs eee ceceeeee BL O Lago while ee BT O Lace do-while - 84 Comandos de Desvio 85 O Comando return . 285 O Comando goto ... +86 © Comando break . 86 A Funcao exit)... - 88 © Comando continue - 89 Comandos de Expressées : feeee vee 91 Blocos de Comandos ......60066062000000 . cece OL Matrizes @ Strings .... 0.6.6 e cece cece cece eee ee ee teen cree es OD Matrizes Unidimensionais . ..... peer ceee eee 92 Gerando um Ponteiro para uma Matriz ee cece OM Passando Matrizes Unidimensionais para Fungdes .......... 02... cee DM Strings 96 Matrizes Bidimensionais ---98 Matrizes de Strings ...... 102 Matrizes Multidimensionais uG 104 Indexando Ponteiros = 105 Inicializagao de Matriz ..... bee 107 Inicializagao de Matrizes Nao-Dimensionadas ...... pubepnonecdl) Um Exemplo com o Jogo-da-Velha seer : 109 Ponteiros .........++ ee eee Bee eee eee eee eee eer atts) O Que Sao Ponteiros? ......... - pees 5 ceeeeegils) Varidveis Ponteiros settee oe 5 cee IB Os Operadores de Ponteiros ceteee ails Expressdes com Ponteiros 116 Atribuicao de Ponteiros ceeeees voce teteseteeneeeees 116 Aritmética de Ponteiros bocce ttetettteeteeeeeetersereeteeeess 116 Comparagao de Ponteiros . 118 Ponteiros e Matrizes ....... Bboeoneee coe ween 120 Matrizes de Ponteiros .........0....5 cevceee eee : 2121 Indiregao Multipla . ern weveeee 122 Inicializagao de Ponteiros .. : wo 124 Ponteiros para Fungées ... : poe08H ee 126 Vit C — Completo e Total As Fungées de Alocagao Dinamica em C 128 Matrizes Dinamicamente Alocadas 130 Problemas com Ponteiros. 133 L7. Jospocnousoapepbononnsoccodenocondonsupsuopanoonoo0 EL) A Forma Geral de uma Fungdo .....0606022 502+ 138 Regras de Escopo de Fungées ; 5 139 Argumentos de Fungdes . 139 Chamada por Valor, Chamada por Referéncia . 140 Criando uma Chamada por Referéncia 141 Chamando Fungdes com Matrizes 142 argc e argv — Argumentos para main() 147 O Comando return 5 150 Retornando de uma Fungao .. : 150 Retornando Valores .... 152 Fungdes Que Devolvem Valores Nao-Inteiros 154 Prototipos de Fungdes -- 156 Retornando Ponteiros = 158 Fung@es do Tipo void - 159 © Que main) Devolve? - 160 Recursao . 160, Declarando uma Lista de Parametros de Extensio Variavel +162 Declaracao de Parametros de Fungdes Moderna Versus Classica 162 Questdes sobre a Implementacio : - 164 Parametros e Fungoes de Propésite Geral 164 Eficiéncia 164 Bibliotecas e Arquivos v2 165 Arquivos Separados vee 165 Bibliotecas . : 165 De Que Tamanho Deve Ser um Arquivo de Programa? . 166 Estruturas, Unides, Enumeracées e Tipos Definidos pelo Usuario .... 167 Estruturas . 167 Referenciando Elementos de Estruturas 169 Atribuicao de Estruturas 170 Matrizes de Estruturas 171 Um Exemplo de Lista Postal 171 Passando Estruturas para Fungies 179 Passando Elementos de Estrutura para Fungoes . 179 Passando Estruturas Inteiras para Funcées . . 180 Ponteiros para Estruturas cee feces = 182 Declarando um Ponteiro para Estrutura ...... 00.22.22. - 182 Usando Ponteiros para Estruturas .... : : =. 182 Matrizes e Estruturas Dentro de Estruturas 185, Campos de Bits 186 Sumério IX Unides eee eee e eee ee beeen eee . eeeeeeeeee eens Enumeragbes BapaeHo eo! Usando sizeof para Assegurar Portabilidade ........ Beene od typedef Seen eee eter eee eee cee ety o6) B. E/S pelo Console .........e0eeeee eens eee Erneta re aber Lendo e Escrevendo Caracteres eee ee eee roo Um Problema com getchar() ......... 200 Alternativas para getchar() .......... +200 Lendo e Escrevendo Strings .........0605 2201 E/S Formatada pelo Console « beveeveestsseeetteseeerternaeseer ©1203 printf0 5 beceeeteveeeee ees 1.204 Escrevendo Caracteres : sete +205 Escrevendo Niimeros ........ : beceeetee +. 205 Mostrando um Endereco voce vceneteete reese e206 O Especificador fon .....-..-. veveee ee 207 Modificadores de Formato. . beveveeeeee ees 207 O Especificador de Largura Minima de Campos... 0. . = 207 O Especificador de Precisd0 ........00s00ceeecseeeeessesseeseeeess 209 Justificando a Saida....... vette ttttnteeeeeens cece ee 210 Manipulando Outros Tipos de Dados : 210 Os Modificadores * ¢ # 5 210 seanf()........... 2 Especificadores de Formato .......s....5 : 212 Inserindo Nuimeros ..... cee 212 Inserindo Inteiros sem Sinal_ feeteeteettnteeeeeeeseterseee 213 Lendo Caracteres Individuais com sean{).........0000000+ 213 Lendo Strings ... feetevtcnneernens eee 213 Inserindo um Endereco |... 24 O Especificador % occ 215 Utilizando um Scanset 215 Deseartando Espacos em Branco Indesejados . 216 Caracteres de Espaco Nao-Branco na String de Controle .............-..--.216 Deve-se Passar Enderegos para seanf() .......0000c00seecseeeeeeeeeeeersees216 Modificadores de Formato Suprimindo a Entrada 9. E/S com Arq See eee eee ee eee eee Eee ee Teri o) E/S ANSI Versus E/S UNIX ceveeeeseeees cece eee 219 217 218 E/S em C Versus E/S em C++ : : +220 Streams e Arquivos . , : 220 Streams ... : 220 Streams de Texto oo .s.ccss. eee nrrereer en 221 Streams Binérias ..... : beettteeeees 221 Arquivos ...... 1221 C— Completo.e Total Fundamentos do Sistema de Arquivos ..........0000006000ecceceeeeeeeee ee 222 O Ponteiro de Arquivo Bopode . veer 2B Abrindo um Arquivo veces cover e een 224 Fechando um Arquivo sevens fever eee e e225 Escrevendo um Caractere : ; - 226 Lendo um Caractere +226 Usando fopen0), getc(), putc() e fclose() tees +227 Usando feof() . . +228 Trabalhando com Strings: ‘puts e fgets vee 230 TeWINd() 2.0... ccc eeeeeeeeeeeeeeeeteeetseeeeeeteeeetretectterereeseese231 ferror() ....... beet t tt nttreeeeees eee 232 Apagando Arquivos ..........2-00005 ceteees ceceeeee nee 234 Esvaziando uma Stream beeen b ce tnteeteeeteeee tener 235 fread() e fwrite() coven 235 Usando fread() e fwrite) : 5 235 fseek() e E/S com Acesso Aleatério ceceeeeeee e242 fprintf) e fscanf) coven eee MB As Streams Padrao 2245 ‘A Conexio de E/S pelo Console . . 245 Usando freopen() para Redirecionar as Streams Padro.......s...... 246 O Sistema de Arquivo Tipo UNIX ...... feeeeees veeeeee e247 open() fees feet e cet trsneeteeeeeeen ere 1 248 creat() . : . coven 249) close) . sees wees foe cee 249) read() e write() vee ceeeeeeteetteeeeeteeteee rere 250 unlink() : eee veteees 222251 Acesso Aleat6rio Usando Iseek() beet eeeennnneeeeeeeee ees 252 |. © Pré-processador de C e Comentarios .......- 200s eee cere eens 254 O Pré-processador de Co... fees seen 254 define .. vette ete tcvtneeeeeeseeeener ee 0285 Definindo Macros Semelhantes a FungSes....0..0cccccscse beeeeee 1287 #error +258 include : veces 1 . Diretivas de Compilagao Condicional beseeeeeee veeeee e259 Hif, Helse, Helif e #endif ..............005 feeteeecevenrreeeeneesess1259 Hifdef e Hite 00... eeeeee eee fesse 261 #undef .. cove vc tevvsseetesteeteettnereaees 262 Usando defined 263 Hine . ve tet ee tecvttreeeeeteteeteesttttsteteetertreeesersss 2264 fipragma....... fete teteestreeereesenneee sees +264 Os Operadores # © ## do Pré-processador veeetneeeeeeeetee 2+ 264 Nomes de Macros Predefinidas ........2.200c00ccseeseceseeeeeennnsteeees+ +266 Comentarios 00.6... coe cece eee eeeseceneceeeteecteesenet nese oces - 266 Sumdrio XI Parte 2 — A Bibl teca C Padréo 11, Linkedigéo, Bibliotecas e Arquivos de Cabecalho O Linkeditor Compilagdo Separada . Cédigo Relocavel ...... Linkeditando com Overlays Linkeditando com DLLs A Biblioteca C Padrao Arquivos de Biblioteca Versus Arquivos-Objetos . Arquivos de Cabecalho . beeeee Macros em Arquivos de Cabecalho Redefinigdo das Fungées da Biblioteca . 12, Fungoes de E/S.....-... pee eer 13. Fungées de String e de Coracteres ........ 4.065 14, Fungdes Mateméticas ....... 66... cece eee cee eee e eee eee a 15. Fungées de Hora, Data e Outras Relacionadas com o Sistema... 16. Alocagéo Dinémica.......... 6.005 Pee Eee eee eee Cee eereer 17. Fungées Graficas e de Texto .... 60.6 e ee ece ee eee ee eee ent enene 442 18, Fungdes Miscelaneas .............-0--0 06 Seen cece eee eevee .. 472 Parte 3 — Algoritmos e Aplicagées ...... 19. Ordenagéo e Pesquisa .. peer Ordenacao Tipos de Algoritmos de Ordenacao Uma Avaliagio dos Algoritmos de Ordenacao A Ordenagao Bolha — O Deménio das Trocas .. Ordenacao por Selecéo Ordenacao por Insergio Ordenagées Melhores Ordenacao Shell Quicksort Escolhendo uma Ordenagao Ordenando Outras Estruturas de Dados Ordenagao de Strings ....... Ordenacao de Estruturas : Ordenando Arquivos de Acesso Aleatorio em Disco Pesquisa . Métodos de Pesquisa xi C—Completo e Total Pesquisa Seqiiencial feet coer BBB Pesquisa Bindtia - eee 23 20. Filas, Pilhas, Listas Encadeadas e Arvores Bindrias .............. 525 Fila oo... fee tteeeee oe - 526 A Fila Circular... vevceeeees ve 531 Pilhas bette teteeee serene Sas) Listas Encadeadas Hoobddnb popun0606 540 Listas Singularmente Encadeadas Listas Duplamente Encadeadas Um Exemplo de Lista Postal Arvores Bindrias . 21. Matrizes Esparsas ...... ‘A Matriz Esparsa com Lista Encadeada da Abordagem com Lista Encadeada | A Abordagem com Arvore Binaria para Matriz Esparsa Anélise da Abordagem com Arvores Binétias ‘A Abordagem com Matriz de Ponteiros para Matriz Esparsa Andlise da Abordagem com Matriz de Ponteiros de Hashing ... Escolhendo uma Abordagem . 22, Andlise de Expressées e Avaliagao ........+- Expressdes : Dissecando uma Expressio Anilise de Expressio .. : Um Analisador Simples de Expressdes Acrescentando Variaveis ao Analisador . Verificagao de Sintaxe em um Analisador Recursive Descendente 23. Solucdo de Problemas de Inteligéncia Artifical ........ Representacao ¢ Terminologia Explosies Combinatorias Técnicas de Pesquisa Avaliagao das Pesquisas Uma Representacao Grafica : A Pesquisa de Profundidade Primeiro .. i Uma Analise da Pesquisa de Profundidade Primeiro .. A Pesquisa de Extensdo Primeiro .... sees Uma Anidlise da Pesquisa de Extenso Primeiro Adicionando Heuristicas . A Pesquisa da Escalada da Montanha Anélise da Escalada da Montanha Sumario Xi A Pesquisa por Menor Esforgo ee vette bee 635) Andlise da Pesquisa por Menor Esforgo feet tenet n ee ee terre 636 Escolhendo uma Técnica de Pesquisa cece eee 637 Encontrando Multiplas Solugdes » 637 526 Remogao de Percurso eee eee 638 Remogao de NO . : 639 Encontrando a Solucéo Ideal 645 De Volta as Chaves Perdidas ... votes 651 24. Construindo o Esqueleto de um Programa Windows 95 ........... 655 A Perspectiva da Programagao Windows 95 ; = 656 O Modelo da Mesa de Trabalho . : ++ 656 O Mouse .......ceeeeeeeerreeeee betes cree e687 [cones e Mapas de Bits 657 Menus, Barras de Ferramentas, Barras de Status e Caixas de Didlogo 657 Como Windows 95 e Seu Programa Interagem 658 Windows 95 Usa Multitarefa Preemptiva 659 A API Win32: A API de Windows 95 ....... 659 Os Componentes de uma Janela ...... : : cee 660 Nocées Basicas sobre Aplicagées Windows 95. -661 WinMain() . . wee eee eee . . 661 A Fungao de Janela.........0000ccsevveseee veeees cece 662 Classes de Janelas 00.0.0... 662 A Repeticio de Mensagens . on 663 Os Tipos de Dados Windows .. ao 663 Um Esqueleto Windows 95 664 Definindo a Classe de Janela 667 Criando uma Janela 669 A Repeticio de Mensagens 671 A Fungao de Janela feeetevereeteteeteeteessrerses e673 Usando um Arquivo de Definicao Serene peeeereer Oc Convenes sobre Nomes 0... .....:::ccceeeee feeee eee 674 Parte 4 — Desenvolvimento de Software Usando C............00+4++ 677 25. Interfaceamento com Rotinas em Linguagem Assembly ........... 679 Interface com a Linguagem Assembly ...... : 679 As Convengdes de Chamada de um Compilador C 681 ‘As Convengdes de Chamada do Microsoft C/C++ 681 Criando uma Fungao em Cédigo Assembly +683 Uma Fungao Simples em Cédigo Assembly 683 Um Exemplo de Chamada por Referéncia 688 Utilizando 0 Modelo de Meméria Grande para Dados Codigo 690 Criando um Esqueleto de Cédigo Assembly ............5 ves 692 xiv C— Completa ¢ Total ‘Usando asm 7 = 694 Quando Codificar em Assembler. - 695 26. Engenharia de Software Usando C .... 6... cece cece eee s OIF Projeto em Top-DOWN 2.0... 000.2 00 eeeeeeeeee eee oo Delineando Seu Programa cee 698 Escolhendo uma Estrutura de Dados . .. 699 Fungoes a Prova de Bala .........- 700 Usando MAKE . 703 Usando Macros com MAKE cet eetteeeee ees 707 Usando um Ambiente Integrado de Desenvolvimento 708 , Portabilidade e Depuragao .......... 66.0.6. 05 ++ 710 710 Os Operadores de Incremento ¢ Decremento seteteeeeteeeeereee TIT Utilizando Variaveis em Registradores .............. 712 Ponteiros Versus Indexagao de Matrizes .......... 715 Uso de Fungées 716 Programas Portavei .720 Usando #define beens see . 1 72D Dependéncias do Sistema Operacional «0.0... .s..-. 721 Diferencas no Tamanho dos Dados ; 722 Depuragéo 723 Erros de Ordem de Processamento . 1 7B Problemas com Ponteiros .. 2.724 Erros Bizarros de Sintaxe ..............4... eee wes 726 Erros por Um ... 727 Erros de Limites . -728 Omissio de Prototipo de Funcio. 729 Erros de Argumentos 730 Colisées entre a Pilha eo Heap . 731 Teoria Geral de Depuragio 731 A Arte da Manutencao de Programas ............... 1733 Consertando Erros oe 733 Protegao do Cédigo-Fonte -734 Parte 5 — Unt Interpretador ©... 2... .ccc eee eceee ence eee enees 737 28, Interpretadores C...... 6c cece cece e eee ens ees eee e ene e ens 139 A Importancia Pratica dos Interpretadores ... See 740 A Especificagio de Little C i -7AL Uma Restricao Importante de Little C ...... 742 Interpretando uma Linguagem Estruturada 743 Uma Teoria Informal de C 744 Expressées C 745 Sumério xv Avaliando Expresses ....... 00000. 0e cece cee e eee eee ee eee eens 746 © Analisador de Express6es ... bevtecerseeee 747 Reduzindo 0 Cédigo-Fonte a Seus Componentes... : 748 Analisador Recursivo Descendente Little C : 755 Interpretador Little C 7 768 A Varredura Prévia do Interpretador . fetet tees 769 A Fungao Main0 een bectetsneeeeeeteertrceensnssT22 A Funcao Interp block ......0000c0cccseceeeeee eee veveeeree 7B Tratando Varidveis Locais 789 Chamando Fungdes Definidas pelo Usuario cect e ete ceree eee ee ees 2 790 Atribuindo Valores a Varidveis vee ee 794 Executando um Comando if ......600c00c0cceeeeeeeeeeevsssseeeeeeesees 20795 Processando um Lago While .....00000000000¢00000cerereeeees 2.79 Processando um Lago Do-While ............ beeteeeees 797 O Lago for eens 798 Fungdes da Biblioteca Little C . feeee eee etr ere e es 799 Compilando e Linkeditando o Interpretador Little Co... es scceceesess 1803 Demonstrando Little Co... ...ecceecccsessseeseeeseeceerenssaeeeeesee ss 1804 Melhorando Little Co... 0... ...eceeeecceesseeeeseeseeeeneeenes 807 Expandindo Little C........ en 809 Adicionando Novos Recursos de Cs... 809 Adicionando Recursos Auxiliares sete eee . 810 indice Analitico . MAKRON Books Parte 1 A Linguagem C A primeira parte deste livro apresenta uma discussao completa da linguagem de programacao C. O Capitulo 1 fornece uma rapida exposicao da linguagem C — o programador mais experiente talvez queira passar diretamente para o Capitulo 2. O Capitulo 2 examina os tipos de dados internos, varidveis, operadores e expressées. O Capitulo 3 apresenta os comandos de controle do programa. O Capitulo 4 discute matrizes e strings. O Capitulo 5 trabalha com ponteiros. O Capitulo 6 discute funcdes. O Capitulo 7 aborda estruturas, unides 0s tipos definidos pelo usuario. O Capitulo 8 examina as E/S pelo console. O Capitulo 9 aborda as E/S de arquivo e, finalmente, 0 Capitulo 10 discute o pré-processador e faz comentarios. O assunto desta parte (e a maior parte do material deste livro) reflete 0 padrao ANSI para C. No entanto, o padrao original de C, oriundo do UNIX versio 5, também é focalizado, e as diferencas mais importantes sao salientadas. O livro aborda tanto o C ANSI quanto o original como garantia de que vocé encontrara informagées pertinentes ao seu ambiemte de programagao em C. ‘iste Uma Visao Geral de C Se A finalidade deste capitulo é apresentar uma visao geral da linguagem de pro- gramagao C, suas origens, seus usos e sua filosofia. Este capitulo destina-se prin- cipalmente aos novatos em C. Biaso igens de C A linguagem C foi inventada e implementada primeiramente por Dennis Ritchie em um DEC PDP-11 que utilizava o sistema operacional UNIX. C é 0 resultado de um processo de desenvolvimento que comegou com uma linguagem mais antiga, chamada BCPL, que ainda esta em uso, em sua forma original, na Europa. BCPL foi desenvolvida por Martin Richards e influenciou uma linguagem cha- mada B, inventada por Ken Thompson. Na década de 1970, B levou ao desen- volvimento de C. Por muitos anos, de fato, o padrao para C foi a versdo fornecida com 0 sistema operacional UNIX versao 5. Ele é descrito em The C Programming Lan- guage, de Brian Kernighan e Dennis Ritchie (Englewood Cliffs, N.J.: Prentice Hall, 1978). Com a popularidade dos microcomputadores, um grande ntimero de im- plementacoes de C foi criado. Quase que por milagre, os cdigos-fontes aceitos por essas implementacées eram altamente compativeis. (Isto é, um programa escrito com um deles podia normalmente ser compilado com sucesso usando-se um outro.) Porém, por nao existir nenhum padrao, havia discrepancias. Para remediar essa situagao, o ANSI (American National Standards Institute) estabe- leceu, no vero de 1983, um comité para criar um padrao que definiria de uma vez por todas a linguagem C. No momento em que esta obra foi escrita, 0 comité 4 C—Completo e Total Cap. 1 do padrao ANSI estava concluindo 0 processo formal de adogao. Todos os prin- cipais compiladores C j4 implementaram 0 padrao C ANSI. Este livro aborda totalmente o padrao ANSI e enfatiza-o. Ao mesmo tempo, ele contém informa- cOes sobre a antiga versio UNIX de C. Em outras palavras, independentemente do compilador que esteja usando, vocé encontrar assuntos aplicdveis aqui. @ cE uma L nguagem de Meédio Nivel C ¢ freqiientemente chamada de linguagem de médio nivel para computadores. Isso nao significa que C seja menos poderosa, dificil de usar ou menos desen- volvida que uma linguagem de alto nivel como BASIC e Pascal, tampouco implica que C seja similar a linguagem assembly e seus problemas correlatos aos usua- ios. C é tratada como uma linguagem de médio nivel porque combina elementos: de linguagens de alto nivel com a funcionalidade da linguagem assembly. A Ta- bela 1.1 mostra como C se enquadra no espectro das linguagens de computador. Tabela 1.1. A posicéo de C no mundo das linguagens. Nivel mais alto Ada Medula-2 Pascal COBOL FORTRAN BASIC Médio nivel CH c FORTH Macro-assembler Nivel mais baixo Assembler Como uma linguagem de médio nivel, C permite a manipulagao de bits, bytes e enderecos — os elementos basicos com os quais 0 computador funciona. Um cédigo escrito em C é muito portavel. Portabilidade significa que é possivel adaptar um software escrito para um tipo de computador a outro. Por exemplo, se vocé pode facilmente converter um programa escrito para DOS de tal forma a executar sob Windows, entao esse programa é portavel. Todas as linguagens de programagio de alto nivel suportam 0 conceito de tipos de dados. Um tipo de dado define um conjunto de valores que uma varidvel pode armazenar e 0 conjunto de operacdes que pode ser executado com Cap. 1 Uma visto geral de C wo essa varidvel. Tipos de dados comuns sao inteiro, caractere ¢ real. Embora C tenha cinco tipos de dados internos, ela nao ¢ uma linguagem rica em tipos de dados como Pascal e Ada. C permite quase todas conversdes de tipos. Por exem- plo, os tipos caractere e inteiro podem ser livremente misturados na maioria das expressdes. C nao efetua nenhuma verificacao no tempo de execugao, como a validacao dos limites das matrizes. Esses tipos de verificacdes sao de responsa- bilidade do programador. As vers6es originais de C nao realizavam muitos (se é que realizavam algum) testes de compatibilidade entre um parametro de uma funcao e 0 argu- mento usado para chamar a funcao. Por exemplo, na versao original de C, vocé poderia chamar uma funcdo, usando um ponteiro, sem gerar uma mensagem de erro, mesmo que essa fungao tivesse sido definida, na realidade, como recebendo um argumento em ponto flutuante. No entanto, 0 padrao ANSI introduziu o conceito de protdtipos de fungdes, que permite que alguns desses erros em potencial sejam mostrados, conforme a intengao do programador. (Prototipos serao discu- tidos mais tarde no Capitulo 6.) Outro aspecto importante de C é que cle tem apenas 32 palavras-chaves (27 do padrao de fato estabelecido por Kernighan e Ritchie, mais 5 adicionadas pelo comité ANSI de padronizacao), que sao os comandos que compoem a lingua- gem C. As linguagens de alto nivel tipicamente tém varias vezes esse numero de palavras reservadas. Come comparacao, considere que a maioria das versdes de BASIC possuem bem mais de 100 palavras reservadas! @ cE uma Linguagem Estruturada Embora 0 termo linguagem estruturada em blocos nao seja rigorosamente aplicavel aC, ela é normalmente referida simplesmente como linguagem estruturada. C tem muitas semelhancas com outras linguagens estruturadas, como ALGOL, Pascal e Modula-2. KN NOTA: A razio pela qual C nao &, tecnicamente, uma linguagem estruturada em =” locos, é que as linguagens estruturadas em blecos permitem que procedimentos e fungées sejam declarados dentro de procedimentos e fungées. No entanto, como C nio permite a criagto de fungdes dentro de fungoes, niio pode ser chamada formal mente de uma linguagem estruturada em blocos. A caracteristica especial de uma linguagem estruturada é a compartimen- talizagdo do cédigo e dos dados. Trata-se da habilidade de uma linguagem seccionar e esconder do resto do programa todas as informacées nece: rias para se realizar uma tarefa especifica. Uma das maneiras de conseguir 6 ‘C — Complete e Total Cap. 1 essa compartimentalizacao é pelo uso de sub-rotinas que empregam varidveis locais (temporarias). Com 0 uso de variaveis locais é possivel escrever sub-rotinas de forma que os eventos que ocorrem dentro delas ndo causem nenhum efeito inesperado nas outras partes do programa. Essa capacidade permite que seus programas em C compartilhem facilmente secdes de cédigo. Se vocé desenvolve fungdes compartimentalizadas, so precisa saber 0 que uma fungao faz, nao como ela faz. Lembre-se de que 0 uso excessivo de variaveis globais (variaveis conhe- cidas por todo o programa) pode trazer muitos erros, por permitir efeitos cola- terais indesejados. (Qualquer um que ja tenha programado em BASIC esté bem ciente deste problema.) Uma linguagem estruturada permite muitas possibilidades na progra- magao. Ela suporta, diretamente, diversas construgdes de lagos (loops), como while, do-while e for. Em uma linguagem estruturada, 0 uso de goto é proibido ou desencorajado e também a forma comum de controle do programa, (que ocorre em BASIC e FORTRAN, por exemplo). Uma linguagem estruturada permite que voc insira sentengas em qualquer lugar de uma linha e nao exige um conceito rigoroso de campo (como em FORTRAN). A seguir estao alguns exemplos de linguagens estruturadas e nao estru- turadas. Nao estruturadas Estruturadas FORTRAN Pascal BASIC Ada COBOL, CH e Modula-2 Linguagens estruturadas tendem a ser modernas. De fato, a marca de uma linguagem antiga de computador é nao ser estruturada. Hoje, a maioria dos programadores considera as linguagens estruturadas mais faceis de programar e fazer manutencao. O principal componente estrutural de C é a fungdo — a sub-rotina iso- lada de C. Em C, funcées sao os blocos de construgéo em que toda a atividade do programa ocorre. Elas admitem que vocé defina e codifique separadamente as diferentes tarefas de um programa, permitindo, entdo, que seu programa seja modular. Apés uma fungéo ter sido criada, vocé pode esperar que ela trabalhe adequadamente em varias situacOes, sem criar efeitos inesperados em outras par- tes do programa. O fato de vocé poder criar fungGes isoladas é extremamente importante em projetos maiores nos quais um cddigo de um programador nao deve afetar acidentalmente o de outro. Cap. 1 ‘Uma visto gerat de C 7 Uma outra maneira de estruturar e compartimentalizar 0 cédigo em C é pelo uso de blocos de cddigo. Um bloco de cédigo é um grupo de comandos de programa conectado logicamente que é tratado como uma unidade. Em C, um bloco de cédigo ¢ criado colocando-se uma seqiiéncia de comandos entre chaves. Neste exemplo, if (x < 10) { printf ("muito baixo, tente novamente\n") ; scanf("%d", &x); } os dois comandos apés 0 if ¢ entre chaves sao executados se x for menor que 10. Esses dois comandos, junto com as chaves, representam um bloco de cédigo. Eles sao uma unidade légica: um dos comandos nao pode ser executado sem que © outro também seja. Atente para o fato de que todo comando em C pode ser um comando simples ou um bloco de comandos. Blocos de cédigo permitem que muitos algoritmos sejam implementados com clareza, elegancia e eficiéncia. Além disso, eles ajudam o programador a conceituar a verdadeira natureza da rotina. @ ce uma Linguagem para Programadores Surpreendentemente, nem todas as linguagens de computador sao para progra- madores. Considere os exemplos classicos de linguagens para nao-programado- res: COBOL e BASIC. COBOL nao foi destinada para facilitar a vida do progra- mador, aumentar a seguranca do cédigo produzido ou a velocidade em que o cédigo pode ser escrito. Ao contrario, COBOL foi concebida, em parte, para per- mitir que nao-programadores leiam e presumivelmente (embora isso seja impro- vavel) entendam o programa. BASIC foi criada essencialmente para permitir que nao-programadores programem um computador para resolver problemas relati- vamente simples. Em contraposicao, C foi criada, influenciada e testada em campo por programadores profissionais. O resultado final é que C dé ao programador o que ele quer: poucas restrig6es, poucas reclamacées, estruturas de bloco, fungdes isoladas e um conjunto compacto de palavras-chave. Usando C, um programador pode conseguir aproximadamente a eficiéncia de cédigo assembly combinada com a estrutura de ALGOL ou Modula-2, Nao é de admirar que C seja trangiii- lamente a linguagem mais popular entre excelentes programadores profissionais. 8 C— Completo e Total Cap. 1 O fato de C freqiientemente ser usada em lugar da linguagem assembly 6 0 fator mais importante para a sua popularidade entre os programadores. A linguagem assembly usa uma representagao simbélica do cédigo binario real que o computador executa diretamente. Cada operacao em linguagem assembly leva a uma tarefa simples a ser executada pelo computador. Embora a linguagem assembly dé aos programadores 0 potencial de realizar tarefas com maxima fle- xibilidade e eficiéncia, é notoriamente dificil de trabalhar quando se esta desen- volvendo ou depurando um programa. Além disso, como assembly nao é uma linguagem estruturada, o programa final tende a ser um cédigo “espaguete” — um emaranhado de jumps, calls e indices. Essa falta de estrutura torna os pro gramas em linguagem assembly dificeis de ler, aperfeicoar e manter. Talvez ma importante: as rotinas em linguagem assembly nao sao portaveis entre maquinas com unidades centrais de processamento (CPUs) diferentes. Inicialmente, C era usada na programacio de sistema. Um programa de istema forma uma porcao do sistema operacional do computador ou de seus utilitarios de suporte. Por exemplo, os programas que seguem sao freqiientemen- te chamados de programas de sistema Sistemas operacionais Interpretadores Editores Programas de planilhas eletronicas Compiladores ™ Gerenciadores de banco de dados Em virtude da sua portabilidade e eficiéncia, a medida que C cresceu em popularidade, muitos programadores comecaram a usé-la para programar todas as tarefas. Por haver compiladores C para quase todos os computadores, é possivel tomar um cédigo escrito para uma maquina, compilé-lo e rodé-lo em outra com pouca ou nenhuma modificacao. Esta portabilidade economiza tempo e dinheiro. Os compiladores C também tendem a produzir um cédigo-objeto muito compacto e rapido — menor e mais rapido que aquele da maioria dos compiladores BASIC, por exemplo. Além disso, os programadores usam C em todos os tipos de trabalho de programacao porque eles gostam de C! Ela oferece a velocidade da linguagem assembly e a extensibilidade de FORTH, mas poucas das restricdes de Pascal ow Modula-2, Cada programador C pode, de acordo com sua propria personalidade, criar e manter uma biblioteca tinica de fungdes customizadas, para ser usada em muitos programas diferentes. Por admitir — na verdade encorajar — a compi- lacao separada, C permite que os programadores gerenciem facilmente grandes projetos com minima duplicacao de esforco. Cap. 1 Uma visiio geral de C 9 @ Compiladores Versus Interpretadores Os termos compiladores e interpretadores referem-se & maneira como um programa é executado. Existem dois métodos gerais pelos quais um programa pode ser executado. Em teoria, qualquer linguagem de programagio pode ser compilada ou interpretada, mas algumas linguagens geralmente sao executadas de uma ma- neira ou de outra. Por exemplo, BASIC é normalmente interpretada e C, compi- lada (especialmente no auxilio 4 depuragao ou em plataformas experimentais como a desenvolvida na Parte 5). A maneira pela qual um programa é executado nao é definida pela linguagem em que ele é escrito. Interpretadores e compiladores sao simplesmente programas sofisticados que operam sobre o cédigo-fonte do seu programa. Como a diferenca entre um compilador e um interpretador pode nao ser Clara para todos os leitores, a breve descricao seguinte esclareceré o assunto. Um interpretador lé 0 cédigo-fonte do seu programa uma linha por vez, executando a instrugdo especifica contida nessa linha. Um compilador lé pro- grama inteiro e converte-o em um cédigo-objeto, que é uma tradugio do cédigo- fonte do programa em uma forma que 0 computador possa executar diretamente. cédigo-objeto é também conhecido como cédigo bindrio ou cédigo de maquina Uma vez que o programa tenha sido compilado, uma linha do cédigo-fonte, mesmo alterada, nao é mais importante na execucao do seu programa. Quando um interpretador 6 usado, deve estar presente toda vez que vocé executar o seu programa. Por exemplo, em BASIC vocé precisa primeiro executar © interpretador, carregar seu programa e digitar RUN cada vez que quiser usé-lo. O interpretador BASIC examina seu programa uma linha por vez para correcao e entSo executa-o. Esse processo lento ocorre cada vez que o pro- grama for executado. Um compilador, ao contrario, converte seu programa em um cédigo-objeto que pode ser executado diretamente por seu computador. Como © compilador traduz seu programa de uma s6 vez, tudo 0 que vocé precisa fazer 6 executar seu programa diretamente, geralmente apenas digitando seu nome. Assim, o tempo de compilacao sé é gasto uma vez, enquanto o cédigo interpre- tado incorre neste trabalho adicional cada vez que o programa executa. I A Forma de um Programa em C A Tabela 1.2 lista as 32 palavras-chave (ou palavras reservadas) que, combinadas com a sintaxe formal de C, formam a linguagem de programagio C. Destas, 27 foram definidas pela versdo original de C. As cinco restantes foram adicionadas pelo comité ANSI: enum, const, signed, void e volatile. 10 C— Completo e Total Cap. 1 Tabela 1.2 Uma lista das palavras-chave de C ANSI. auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while Além disso, muitos compiladores C acrescentaram diversas palavras- chave para explorar melhor a organizacio da meméria da familia de processa- dores 8088/8086, que suporta programacado interlinguagens ¢ interrupcoes. Aqui 6 mostrada uma lista das palavras-chave estendidas mais comuns: asm _cs ds es _ss cdecl far huge interrupt near pascal Seu compilador pode também suportar outras extensdes que ajudem a aproveitar melhor seu ambiente especifico. Todas as palavras-chave de C sao miniisculas. Em C, maitisculas e mi- ntisculas sao diferentes: else 6 uma palavra-chave, mas ELSE nao. Uma palavra- chave nao pode ser usada para nenhum outro propésito em um programa em C — ou seja, ela nao pode servir como uma varidvel ou nome de uma funcao. Todo programa em C consiste em uma ou mais fungdes. A tinica funcao que necessariamente precisa estar presente 6a denominada mainQ, que é a pri- meira funcao a ser chamada quando a execugao do programa comeca. Em um cédigo de C bem escrito, main() contém, em esséncia, um esboco do que o pro- grama faz. O esboco é composto de chamadas de funcdes. Embora main) nao seja tecnicamente parte da linguagem C, trate-a como se fosse. Nao tente usar main() como nome de uma variavel porque provavelmente confundira 0 com- pilador. A forma geral de um programa em C é ilustrada na Figura 1.1, onde £10 até £NQ representam fungoes definidas pelo usuario. Cop. 1 Uma bisito geval de C n declaragées globais tipo devolvide main(1i ( seqiiéncia de comandos } ta de parametros) tipo devolvido f1(lista de parametros) { seqgilénci } de comandos tipo devolvido £2(lista de pardmetros) { seqiiéncia de comandos } tipo devolvido £NW(lista de parametros) { Figura 1.1 A forma geral de um programa em C. Hf A Biblioteca e a Linkedigao Tecnicamente falando, é possivel criar um programa ttil e funcional que consista apenas nos comandos realmente criados pelo programador. Porém, isso ¢ muito raro porque C, dentro da atual definigao da linguagem, nao oferece nenhum método de executar operagies de entrada /saida (E/S). Como resultado, a maioria dos pro- gyamas inclui chamadas a varias fungdes contidas na biblioteca C padrao. Todo compilador C vem com uma biblioteca C padrao de fungées que realizam as tarefas necessérias mais comuns. O padrao C ANSI especifica 0 con- junto minimo de fungdes que estard contido na biblioteca. No entanto, seu com- pilador provavelmente conter4 muitas outras funcées. Por exemplo, 0 padrao C ANSI nao define nenhuma funcao grafica, mas seu compilador provavelmente inclui alguma. Em algumas implementacées de C, a biblioteca aparece em um grande arquivo; em outras, ela esta contida em muitos arquivos menores, uma organi- zagdo que aumenta a eficiéncia e a praticidade. Porém, para simplificar, este livro usa a forma singular em referénca a biblioteca. 2 C= Completo e Total Cap. Os implementadores do seu compilador C jf escreveram a maioria das fungées de propésito geral que voce usara. Quando chama uma fungao que nao faz parte do programa que vocé escreveu, o compilador C “memoriza” seu nome. Mais tarde, o linkeditor (linker) combina 0 cédigo que vocé escreveu com 0 c6- digo-objeto ja encontrado na biblioteca padrao. Esse processo é chamado de fin- kedicao. Alguns compiladores C tém seu proprio linkeditor, enquanto outros usam © linkeditor padrao fornecido pelo seu sistema operacional As funges guardadas na biblioteca estdo em formato relocdvel. Isso nifica que os enderecos de memoria das varias instrugdes em cédigo de maquina nao estao absolutamente definidos — apenas informacoes relativas s40 guarda- das. Quando seu programa é linkeditado com as fungées da biblioteca padrao, esses enderecos relativos sao utilizados para criar os enderecos realmente usados. Hi diversos manuais ¢ livros técnicos que explicam esse processo com mais de- talhes. Contudo, vocé nao precisa de nenhuma informagio adicional sobre 0 pro- cesso real de relocagio para programar em C. Muitas das fungdes de que vocé precisaré ao escrever seus programas estao na biblioteca padrao. Elas agem como blocos basicos que vocé combina. Se escreve uma funcao que usaré muitas vezes, vocé também pode colocé-la em uma biblioteca. Alguns compiladores permitem que vocé coloque sua funcdo na biblioteca padrao; outros exigem a criagdo de uma biblioteca adicional. De qual- quer forma, o cédigo estar la para ser usado repetidamente. Lembre-se de que 0 padrao ANSI apenas especifica uma biblioteca pa- drao minima. A maioria dos compiladores fornece bibliotecas que contém muito mais fungdes que aquelas definidas pelo ANSI. Além disso, algumas funcdes encontradas na versao original de C para UNIX nao sao definidas pelo padrao ANSI por serem redundantes. Este livro aborda todas as funcées definidas pelo ANSI como também as mais importantes e largamente usadas pelo padrao C UNIX antigo. Ele também examina diversas fungdes muito usadas, mas que nado sao definidas pelo ANSI nem pelo antigo padrao UNIX. (Fungées nao-ANSI serao indicadas para evitar confusac.) @ Compilagao Separada Muitos programas curtos de C estio completamente contidos em um arquivo- fonte. Contudo, quando o tamanho de um programa cresce, também aumenta seu tempo de compilacao (e tempos de compilacao longos contribuem para pa- ciéncias curtas!). Logo, C permite que um programa seja contido em muitos ar- quivos e que cada arquivo seja compilado separadamente. Uma vez que todos 08 arquivos estejam compilados, eles sao linkeditados com qualquer rotina de Cap. 1 Uma visio geral de C 3 biblioteca, para formar um cédigo-objeto completo. A vantagem da compilacdo separada que, se houver uma mudanca no cédigo de um arquivo, nao sera necessaria a recompilagdo do programa todo. Em tudo, menos nos projetos mais simples, isso economiza um tempo considerdvel. (Estratégias de compilagao se- parada sao abordadas em detalhes na Parte 4.) a Compilando um Programa em C Compilar um programa em C consiste nestes trés passos: 1. Criar o programa 2. Compilar o programa 3. Linkeditar o programa com as fungées necessarias da biblioteca Alguns compiladores fornecem ambientes de programagao integrados que incluem um editor. Com outros, € necessario usar um editor separado para criar seu programa. Os compiladores s6 aceitam a entrada de arquivos de texto padrao. Por exemplo, seu compilador nao aceitaré arquivos criados por certos processadores de textos porque eles tém cédigos de controle e caracteres nao- imprimiveis. O método exato que vocé utiliza para compilar um programa depende do compilador que esta em uso. Além disso, a linkedicao varia muito entre os compiladores e os ambientes. Consulte seu manual do usudrio para detalhes. Ho Mapa de Meméria de C Um programa C compilado cria e usa quatro regides, logicamente distintas na mem6ria, que possuem fungdes especificas. A primeira regido é a memoria que contém 0 cédigo do seu programa. A segunda é aquela onde as variaveis globais sao armazenadas. As duas regides restantes sao a pilha eo “heap”. A pilha tem diversos usos durante a execugao de seu programa. Ela possui 0 endereco de retorno das chamadas de fungao, argumentos para funcGes e varidveis locais, Ela também guarda o estado atual da CPU. O heap é uma regido de meméria livre que seu programa pode usar, via fungdes de alocagdo dinamica de C, em apli- cagdes como listas encadeadas e arvores. A disposicao exata de seu programa pode variar de compilador para compilador e de ambiente para ambiente. Por exemplo, a maioria dos compila- dores para a familia de processadores 8086 tem seis maneiras diferentes de or- 4 C~Completo e Total Cap. 1 ganizar a meméria em razao da arquitetura segmentada de meméria do 8086, Os modelos de meméria da familia de processadores 8086 sao discutidos mais adiante neste livro. Embora a disposicao fisica exata de cada uma das quatro regides possa diferir entre tipos de CPU e implementacées de C, 0 diagrama da Figura 1.2 mostra conceitualmente como seu programa aparece na meméria. Pilha | | Heap Varidveis Globais ‘Cédigo do Programa Figure 1.2, Um mapa conceituat de meméria de um programa em C. WC Versus C++ Antes de concluir este capitulo, 6 necessério dizer algumas palavras sobre C++. Algumas vezes os novatos confundem o que é C++ e como difere de C. Para ser breve, C++ é uma versao estendida e melhorada de C que é projetada para su- portar programagao orientada a objetos (OOP, do inglés Object Oriented Pro- gramming). C++ contém e suporta toda a linguagem C e mais um conjunto de extensdes orientadas a objetos. (Ou seja, C++ é um superconjunto de C.) Como C++ 6 construida sobre os fundamentos de C, vocé nao pode programar em C++ se nao entender C. Portanto, virtualmente todo o material apresentado neste livro aplica-se também a C++. 4 NOTA: Para uma descricdo completa da linguagem C++ veja 0 livro, C++ — The void £(voidl; void main(void) ors C — Comapleto ¢ Total } Cap. 2 int i; for(i ; isl0; ies) £0; void f (void) print£("*d ", 3); j++; /* esta linha n&o tem nenhum efeito */ ) Pardmetros Formais Se uma funcdo usa argumentos, ela deve declarar varidveis que receberdo os valores dos argumentos. Essas varidveis sao denominadas pardmetros formais da funcao. Elas se comportam como qualquer outra varidvel local dentro da funcao. Como é mostrado no fragmento de programa seguinte, suas declaragdes ocorrem depois do nome da funcao e dentro dos parénteses: /* Retorna 1 se c é parte da string s; 0 se ndo € o caso */ i (char *s, char c) while(*s) if(*s else s++; ¢) return return 0; ) A funcao is_in@ tem dois parametros: s e ¢. Essa fungdo devolve 1 se 0 caractere especificado em ¢ estiver contido na string 5; 0 se nao estiver. Vocé deve informar & C que tipo de variaveis so os parametros formais, declarando-os como mostrado acima. Uma vez feito isso, elas podem ser usadas dentro da fungao como varidveis locais normais. Tenha sempre em mente que, como variaveis locais, elas também sao dinamicas e sao destruidas na saida da fungao. Vocé deve ter certeza de que os parametros formais que estado declarados sao do mesmo tipo dos argumentos que vocé utiliza para chamar a fungao. Cap.2 Expressbes ean C : 25 Se ha uma discordancia de tipos, resultados inesperados podem ocorrer. Ao con- trario de muitas outras linguagens, C geralmente faré alguma coisa, inclusive em circunstancias nao usuais, mesmo que nao seja o que vocé quer. Ha poucos erros em tempo de execucdo e nenhuma verificagao de limites. Como programador, voce deve ter certeza de que eros de incongruéncia de tipo nao ocorrerao. Embora a linguagem C forneca os protétipos de funcdes, que podem ser usados para ajudar a verificar se os argumentos usados para chamar a fungao sao compativeis com os parametros, ainda podem ocorrer problemas. (Isto é, os protétipos de funcdo nao eliminam inteiramente incongruéncias de tipo de pa- rametro). Além disso, vocé deve incluir explicitamente protétipos de fungdes em seu programa para receber esse beneficio extra. (O uso de prototipos de fungées 6 discutido em profundidade no Capitulo 6.) Analogamente as variveis locais, vocé pode fazer atribuigées a parame- tros formais de uma funcao ou usé-los em qualquer expressdo permitida em C. Embora essas varidveis recebam o valor dos argumentos passados para a funcao, elas podem ser usadas como qualquer outra varidvel local. Varidveis Globais Ao contrario das varidveis locais, as varidueis globnis so reconhecidas pelo pro- grama inteiro e podem ser usadas por qualquer pedaco de cédigo. Além disso, elas guardam seus valores durante toda a execugao do programa. Vocé cria va- ridveis globais declarando-as fora de qualquer funcdo. Elas podem ser acessadas por qualquer expressao independentemente de qual bloco de cédigo contém a expresso. No programa seguinte, a varidvel count foi declarada fora de todas as fungdes. Embora sua declaracao ocorra antes da fungéo main0, ela poderia ter sido colocada em qualquer lugar anterior ao seu primeiro uso, desde que nao estivesse em uma fungao. No entanto, é melhor declarar varidveis globais no inicio do programa. #include int count; /* count é global */ void funcl (void) ; void func2 (void) ; void main(void) count = 100; funcl(}; %6 C— Completo e Total Cap. 2 void funcl (void) { int temp; temp = ccunt; func2 (}; printf (‘count é %d", count); /* imprimiré 100 */ void func2 (void) { int count; for (count=1; count<10; count++) putchar('.'); Olhe atentamente para esse programa. Observe que, apesar de nem main(Q) nem funcl() terem declarado a varidvel count, ambas podem usé-la. A fungéo func2(), porém, declarou uma varidvel local chamada count. Quando fune2() referencia count, ela referencia apenas sua varidvel local, nao a varidvel global. Se uma variavel global e uma variavel local possuem 0 mesmo nome, todas as referéncias ao nome da varidvel dentro do bloco onde a variavel local foi declarada dizem respeito a varidvel local e nao tém efeito algum sobre a varidvel global. Pode ser conveniente, mas esquecer-se disso poder fazer com que seu programa seja exe- cutado estranhamente, embora parega correto. O armazenamento de variaveis globais encontra-se em uma regiao fixa da meméria, separada para esse propésito pelo compilador C. Varidveis globais so titeis quando 0 mesmo dado é usado em muitas funcdes em seu programa. No entanto, vocé deve evitar usar varidveis globais desnecessarias. Elas ocupam meméria durante todo o tempo em que seu programa esta executando, nao ape- nas quando sao necessérias. Além disso, usar uma varidvel global onde uma varidvel local poderia ser usada torna uma fungao menos geral, porque ela conta com alguma coisa que deve ser definida fora dela. Finalmente, usar um grande muimero de varidveis globais pode levar a erros no programa por causa de des conhecidos — e indesejaveis — efeitos colaterais. Isso pode ser evidenciado no BASIC padrao, em que todas as varidveis sao globais. Um problema maior no desenvolvimento de grandes projetos é a mudanca acidental do valor de uma varidvel porque ela é usada em algum outro lugar do programa. Isso pode acon- tecer em C se vocé usar variaveis globais demais em seus programas. Cap.2 Expressdes em C a Uma das principais razdes para uma linguagem estruturada é a com partimentalizago ou separacdo de cédigo e dados. Em C, esse isolamento é con- seguido pelo uso de variaveis locais e fung6es. Por exemplo, a Figura 2.1 mostra duas maneiras de escrever mul{) — uma fungao simples que calcula 0 produto de dois inteiros. Ambas as fungdes retornam 0 produto das varidveis x e y. Contudo, a versao generalizada, ou parametrizada, pode ser usada para retornar o produto de quaisquer dois inteiros, enquanto a versao especifica s6 pode ser usada para encontrar 0 produto das varidveis globais x e y. Geral Especi int x, y; mul(int x, int y) mul( void ) { { return(xty); return (x*y); J ! Figura 2.1. Duas formas de escrever mul0. — Modificadores de Tipo de Acesso O C introduziu dois novos modificadores (também chamados quantificadores) que controlam a maneira como as varidveis podem ser acessadas ou modificadas. Esses modificadores sao const e volatile. Devem preceder os modificadores de tipo e os nomes que eles modificam. const Variaveis do tipo const néo podem ser modificadas por seu programa. (Uma varidvel const pode, entretanto, receber um valor inicial.) O compilador pode colocar varidveis desse tipo em meméria de apenas leitura (ROM). Por exemplo: W const int a= cria uma varidvel inteira chamada a, com um valor inicial 10, que seu programa no pode modificar. Voce pode, porém, usar a varidvel a em outros tipos de expressdes. Uma varidvel const recebe seu valor de uma inicializagao explicita ou por algum recurso dependente do hardware. 28 C-— Completo e Total Cap. 2 O qualificador const pode ser usado para proteger os objetos apontados pelos argumentos de uma fungdo de serem modificados por esta funcdo. Isto 6, quando um ponteiro é passado para uma fungao, esta funcao pode modificar a varidvel real apontada pelo ponteiro. Entretanto, se 0 ponteiro é especificado como const na declaracio dos parametros, 0 cddigo da fung3o nao sera capaz de modificar 0 que ele aponta. Por exemplo, a fungao sp_to_dash0), no programa seguinte, imprime um trago para cada espaco do seu argumento string. Ou me- Thor, a string “isso é um teste” sera impressa “isso-é-um-teste”. O uso de const na declaragao do parametro assegura que 0 cédigo dentro da fungao nao possa modificar 6 objeto apontado pelo parametro. #include void sp_to_dashiconst char *str); void main(void) sp_to_dash("isso 6 um teste"); void sp_to_dash(const char *str) ( while(*str) { if(*str ' 1) printt("’e", '-"); else printf("%c", *str); str++; Se voce escrevesse sp_to_dash() de forma que a string fosse modificada, ela nao seria compilada. Por exemplo, se voce tivesse codificado sp_to_dash() como se- gue, obteria um erro: /* isso esta errado */ void sp_to_dash(const char *str) { while (*str) if("stre=' / ) +str printé("tc", *str); stre+; /* n&o faga isto */ Cap. 2 Expressoes em C 29 Muitas fungées da biblioteca C padrao usam const em suas declaragées de pa- rametros. Por exemplo, a funcao strlen() tem este prototipo: size_t strlen(const char *str); Especificar str como const assegura que strlen() nao modificard a string apontada por str. Em geral, quando uma fungao da biblioteca padrao nao tem necessidade de modificar um objeto apontado por um argumento, ele 6 declarado como const Vocé também pode usar const para verificar se seu programa nao mo- difica uma varidvel. Lembre-se de que uma varidvel do tipo const pode ser mo- dificada por algo externo ao seu programa. Por exemplo, um dispositive de hardware pode ajustar seu valor. Porém, declarando uma varidvel como const, vocé pode provar que qualquer alteracao nesta varidvel ocorre devido a eventos externos. volatile O modificador volatile é usado para informar ao compilador que o valor de uma varidvel pode ser alterado de maneira nao explicitamente especificada pelo pro- grama. Por exemplo, um endereco de uma varidvel global pode ser passado para a rotina de relégio do sistema operacional e usado para guardar 0 tempo real do sistema. Nessa situacao, o contetido da variavel € alterado sem nenhum co- mando de atribuigéo explicito no programa. Isso é importante porque muitos compiladores C automaticamente otimizam certas expressdes, assumindo que o contetido de uma varidvel é imutavel, se sua referéncia nao aparecer no lado esquerdo da expressao; logo, ela pode nao ser reexaminada toda vez que for referenciada. Alem disso, alguns compiladores mudam a ordem de avaliacao de uma expressao durante o processo de compilacao. O modificador volatile previne a ocorréncia dessas mudancas. E possivel usar const e volatile juntos. Por exemplo, se 0x30 6 assumido como sendo 0 valor de uma porta que é mudado apenas por condigées externas, a declaragéo seguinte é precisamente 0 que vocé quer para prevenir qualquer possibilidade de efeitos colaterais acidentais, const volatile unsigned char *port = 0x30; Hf Especificadores de Tipo de Classe de Armazenamento Hé quatro especificadores de classe de armazenamento suportados por C. 30 C— Completo ¢ Total Cap.2 extern static register auto Esses especificadores sao usados para informar ao compilador como a varidvel deve ser armazenada. O especificador de armazenamento precede 0 res- to da declaracao da varidvel. Sua forma geral &: especificador_de_armazenamento tipo nome_da_varidvel; extern Uma vez que C permite que médulos de um programa grande sejam compilados separadamente para entao serem linkeditados juntos, uma forma de aumentar a velocidade de compilacao e ajudar no gerenciamento de grandes projetos, deve haver alguma maneira de dizer a todos os arquivos sobre as varidveis globais solicitadas pelo programa. Lembre-se de que vocé pode declarar uma varidvel global apenas uma vez. Se vocé tentar declarar duas varidveis com 0 mesmo nome dentro do mesmo arquivo, seu compilador C podera imprimir uma men- sagem de erro como “nome de varidvel duplicado” ou poderé simplesmente escolher uma varidvel. © mesmo problema ocorre se vocé simplesmente declara todas as varidveis globais necessarias ao seu programa em cada arquivo. Embora © compilador nao emita nenhuma mensagem de erro em tempo de compilacio, vocé estaria realmente tentando criar duas (ou mais) c6pias de cada varidvel. O transtorno comecaria quando vocé tentasse linkeditar seus médulos. O linke- ditor mostraria a mensagem de erro como “rétulo duplicado” porque ele nao saberia que varidvel usar. A solucdo seria declarar todas as suas varidveis globais em um arquivo e usar declaragGes extern nos outros, como na Figura 2.2. No arquivo 2, a lista de varidveis globais foi copiada do arquivo 1 e especificador extern foi adicionado as declaracées. O especificador extern diz ao compilador que os tipos e nomes de varidvel que o seguem foram declarados em outro lugar. Em outras palavras, extern deixa o compilador saber 0 que os tipes e nomes sao para essas varidveis globais sem realmente criar armazena- mento para elas novamente. Quando o linkeditor unir os dois médulos, todas as referéncias a varidveis externas serao resolvidas. Quando utiliza uma varidvel global dentro de uma fungao que est4 no mesmo arquivo que a declaracao da varidvel global, vocé pode usar extern, como mostrado aqui: Cap. 2 Expressées em C 31 Arquivo 1 Arquivo 2 int x, ys extern int x, y; char ch; extern char ch; main(void) func22(void) ( ( x= y/10; 1 1 func230) { funcl() y= 10; { 1 Figura 2.2. Uso de varidveis globais em médulos compilados separadamente. int first, last /* declaragao global de first e last */ void main(void) { extern int first; /* uso opcional da declaragao extern */ Embora as declaragées de variaveis extern possam ocorrer dentro do mesmo arquivo da declaracdo global, elas nao sio necessdrias. Se 0 compilador C en- contra uma varidvel que nao foi declarada, ele verifica se ela tem 0 mesmo nome de alguma variavel global. Se tiver, o compilador assumira que a variavel global esta sendo referenciada. Variaveis static Dentro de sua prépria funcgao ou arquivo, varidveis static sao varidveis perma- nentes. Ao contrario das variaveis giobais, elas nao sao reconhecidas fora de sua funcao ou arquivo, mas mantém seus valores entre chamadas. Essa caracteristica torna-as titeis quando vocé escreve funcées generalizadas e funcées de biblioteca que podem ser usadas por outros programadores. O especificador static tem efeitos diferentes em varidveis locais e em varidveis globais. 32 © — Completo ¢ Total Cap. 2 Variaveis Locais static Quando 0 modificador static 6 aplicado a uma varidvel local, 0 compilador cria armazenamento permanente para ela quase da mesma forma como cria armaze- namento para uma variavel global. A diferenca fundamental entre uma varidvel local static e uma varidvel global é que a variavel local static é reconhecida apenas no bloco em que estd declarada. Em termos simples, uma varidvel local static é uma varidvel local que retém seu valor entre chamadas de fungao Varidveis locais static sao muito importantes na criagdo de fungodes iso- ladas, porque diversos tipos de rotinas devem preservar um valor entre as cha- madas. Se varidveis static nao fossem permitidas, varidveis globais teriam de ser usadas, abrindo brechas para possiveis efeitos colaterais. Um exemplo de fungao que requer uma varidvel local static € um gerador de série de ntimeros que pro- duz um novo numero baseado no anterior. Seria possivel declarar uma varidvel global para reter esse valor. Porém, cada vez que a funcao € usada, vocé deve lembrar-se de declarar essa varidvel global e garantir que ela nao conflite com nenhuma outra varidvel global ja declarada. Além disso, usar uma variavel global tornaria essa funcao dificil de ser colocada em uma biblioteca de fungées. A melhor solugao € declarar a varidvel que retém o ntimero gerado como static, como neste fragmento de programa series (void) { static int series_num; series_num = series_num+23; return (series_num); ) Nesse exemplo, a varidvel series_num permanece existindo entre as chamadas da funcao em vez da criagio e exclusio que as variéveis locais normais fariam. Isso significa que cada chamada a series() pode produzir um novo membro da série, baseado no ntimero precedente, sem declarar essa varidvel globalmente. Vocé pode dar a varidvel local static um valor de inicializacao. Esse valor é atribufdo apenas uma vez — e nao toda vez que © bloco de cédigo é inserido, de forma andloga as varidveis locais normais. Por exemplo, essa versio de series() inicializa series_num com 100: series (void) i static int series_num = 100; Cap. 2 Expressbesiem C 33 series_num = series_num+23; return series_num; ) Da forma como a fungao se acha agora, a série sempre comega com 0 valor 123. Enquanto isso é aceitavel para algumas aplicagdes, a maioria dos geradores de séries permite ao usuario especificar 0 ponto inicial. Uma maneira de dar a series_num um valor especificado pelo usuario é tornar series_num uma varidvel global e, em seguida, ajustar seu valor de acordo com o especificado. Porém, series_num foi feita static justamente para nao ser definida como global. Isso leva ao segundo uso de static. veis Globais static Aplicar 0 especificador static a uma varidvel global informa ao compilador para criar uma variavel global que é reconhecida apenas no arquivo no qual a mesma foi declarada. Isso significa que, muito embora a varidvel seja global, rotinas em outros arquivos nao podem reconhecé-la ou alterar seu conteido diretamente; assim, nao esta sujeita a efeitos colaterais. Entretanto, para as poucas situacdes onde uma varidvel local static nao possa fazer o trabalho, vocé pode criar um pequeno arquivo que contenha apenas as funcdes que precisam da varidve! glo- bal static e compilar separadamente esse arquivo sem medo de efeitos colaterais. Para ilustrar uma varidvel global static, o exemplo de gerador de série da seco anterior foi recodificado de forma que um valor somente inicialize a série por meio de uma chamada a uma segunda funcao denominada series_start(. O arquivo inteiro, que contém series, series_start() e series_num é mostrado aqui: /* Isso deve estar em um Unico arquivo - preferencialmente isolado. */ static int series_num; void series_start (int seed); int series (void); series (void) t series_num = series_num+23; return series_num; /* inicializa series_num */ void series_start(int seed) { series_num = seed; } Ea C —Completo ¢ Total Cap. 2 Para inicializar o gerador de série, deve-se chamar series_start() com algum valor inteiro conhecido. Depois disso, chamadas a series() geram os proximos elemen- tos da série. Revisando: Os nomes das varidveis locais static sio reconhecidos apenas na fungao ou bloco de cédigo em que elas so declaradas. Os nomes das varid- veis globais static sao reconhecidos apenas no arquivo em que elas residem. Isso significa que, se vocé colocar as fungGes series() e series_start() em uma biblio- teca, poderd usar as fungdes, mas nao podera referenciar a varidvel series_num, que esta escondida do resto do cédigo do seu programa. De fato, vocé pode, inclusive, declarar e usar outra varidvel chamada series_num em seu programa (em outro arquivo, é claro). Em esséncia, 0 modificador static permite varidveis que sao reconhecidas pelas fungdes que precisam delas, sem confundir outras funcdes. As variaveis static admitem que vocé, 0 programador, esconda porcgées de seu programa das outras partes. Isso pode ser uma vantagem imensa quando se tenta gerenciar um programa muito grande e complexo. O especificador de classe de armazenamento static deixa vocé criar fungées gerais que podem ir para bibliotecas que serao utilizadas posteriormente. Varidveis register O especificador de armazenamento register tradicionalmente era aplicado apenas a variaveis dos tipos int e char. Contudo, o padrao C ANSI ampliou sua definigao de forma que ele pode ser aplicado a qualquer varidvel. Originalmente, o especificador register solicitava ao compilador C que armazenasse o valor das varidveis declaradas com esse especificador num regis- trador da CPU em vez da meméria, onde as varidveis normais s4o armazenadas. Isso significa que operacdes nas varidveis register poderiam ocorrer muito mais rapidamente que nas varidveis armazenadas na meméria, pois o valor dessas varidveis era realmente conservado na CPU e nao era necessario acesso & me- moria para determinar ou modificar seus valores. Hoje, uma vez que agora 0 padrao C ANSI permite que vocé modifique qualquer tipo de variavel com register, ele alterou a definicao do que register faz. O padrao C ANSI simplesmente determina que “o acesso ao objeto é 0 mais, rapido possivel”. Na pratica, caracteres e inteiros sao colocados nos registradores da CPU. Objetos maiores, como matrizes, obviamente nao podem ser armazena- dos em um registrador, mas eles ainda podem receber um tratamento diferen- ciado. Dependendo da implementagao do compilador C e de seu ambiente opera- cional, varidveis register podem ser manipuladas de quaisquer formas conside- Cap. 2 Expressbes em C 35 radas cabiveis pelo implementador do compilador. O padrao C ANSI também permite que o compilador ignore o especificador register e trate as varidvei modificadas por ele como se nao fossem, mas isso raramente ocorre na pratica. Vocé s6 pode aplicar o especificador register a varidveis locais e a pa- rametros formais em uma funcao. Assim, varidveis globais register nao sao per- mitidas. Aqui esté um exemplo de como declarar uma variavel register do tipo int e usa-la para controlar um lago. Essa funcao calcula o resultado de M®° para inteiros: int_pwr(register int m, register int e) ( ister int temp; temp = for(; e; e--) temp = temp * mj return temp; ) Neste exemplo, tanto e como m e temp sao declaradas como varidveis register porque sao usadas dentro do laco. O fato de varidveis register serem otimizadas para velocidade torna-as ideais ao controle de laco. Geralmente, variaveis register sao usadas quando mais apropriadas, isto é, em lugares onde so feitas muitas referéncias a uma mesma variavel. Isso é importante porque vocé pode declarar qualquer ntimero de variaveis como sendo do tipo register, mas nem todas re- cebem a mesma otimizagao de velocidade. O ntimero de variaveis em registradores dentro de qualquer bloco de c6digo é determinado pelo ambiente e pela implementagao especifica de C. Vocé nao deve preocupar-se em declarar muitas varidveis register porque o compila- dor C automaticamente transforma varidveis register em varidveis comuns quan- do o limite for alcancado. (Isso é feito para assegurar a portabilidade do codigo em C por meio de uma ampla linha de processadores.) Por todo este livro, muitas varidveis de controle de laco serao do tipo register. Normalmente, pelo menos duas variaveis register do tipo char ou int podem de fato ser colocadas em registradores da CPU. Como os ambientes va- riam enormemente, consulte o manual do usuario do seu compilador para de- terminar se vocé pode aplicar quaisquer outros tipos de opgdes de otimizacoes. Como uma varidvel register pode ser armazenada em um registrador da CPU, varidveis register ndo podem ter enderecos. Isto é, vocé nao pode en- contrar 0 endereco de uma varidvel register usando 0 operador & (discutido mais adiante neste capitulo). 36 C— Completo Total Cap. 2 Embora 0 padrao C ANSI tenha expandido a descrigdo de register, na pratica ele geralmente sé tem um efeito significativo com os tipos inteito e ca- ractere. Logo, vocé provavelmente nao deve contar com aumentos substanciais da velocidade para os outros tipos de varidveis @ Inicializag&o de Variaveis Vocé pode dar A maioria das variéveis em C um valor, no mesmo momento em que elas so declaradas, colocando um sinal de igual e uma constante apés 0 nome da varivel. A forma geral de uma inicializacao é tipo nome_da_varivel = constante; Alguns exemplos sao char ch = ‘a’; int first O; float balance = 123.23; Variaveis globais ¢ varidveis locais static sio inicializadas apenas no comeco do programa. Varidveis locais (incluindo variaveis locais static) sao inicializadas cada vez. que o bloco no qual estao declaradas for inserido. Variaveis locais e register que nao sao inicializadas possuem valores desconhecidos antes de ser efetuada a primeira atribuicao a elas. Varidveis globais nao inicializadas e variaveis locais estaticas sao inicializadas com zero. I constantes Em C, constantes referem-se a valores fixos que 0 programa nao pode alterar. Constantes em C podem ser de qualquer um dos cinco tipos de dados basicos. A maneira come cada constante é representada depende do seu tipo. Constantes de caractere sao envolvidas por aspas simples ('). Por exemplo, ‘a’ e “%’ so constantes tipo caractere. O padrao ANSI também define caracteres multi bytes (usados principalmente em ambientes de \ingua estrangeira). Constantes inteiras so especificadas como mimeros sem componentes fraciondrios. Por exemplo, 10 e -100 so constantes inteiras. Constantes em ponto flutuante requerem o ponto decimal seguido pela parte fracionaria do mimero. Por exemplo, 11.123 é uma constante em ponto flutuante. C também permite que vocé use notagao cientifica para ntimeros em ponto flutuante. Cap. 2 Expresses em C 37 Existem dois tipos de ponto flutuante: float e double. Ha também diversas variacbes dos tipos basicos que vocé pode gerar usando os modificadores de tipo. Por padrao, 0 compilador C encaixa uma constante numérica no menor tipo de dado compativel que pode conté-lo. Assim, 10 é um int, por padrao, mas 60,000 é unsigned e 100.000 é long. Muito embora o valor 10 possa caber em um tipo ca- ractere, 0 compilador nao atravessard os limites do tipo. A tinica excecdo para a regra do menor tipo so constantes em ponto flutuante, assumidas como doubles. Na maioria dos programas que vocé escrevera, os padres do compila- dor sao adequados. Porém, vocé pode especificar precisamente o tipo da cons- tante numérica que deseja por meio da utilizagao de um sufixo. Para tipos em ponto flutuante, se vocé colocar um F apés o niimero, ele sera tratado como float. Se vocé colocar um L, ele se tornard um long double, Para tipos inteiros, 0 sufixo U representa unsigned e 0 L representa long. Aqui estdo alguns exemplo: Tipo de dado fxemplos de constantes int 1 123 21000 -234 long int 35000L, -34L, short int 10 -12 90 unsigned int 10000U 987U 40000 float 123.23F 4.34e-3F double 123.23 12312333. -0.9876324 long double 1001.2L Constantes Hexadecimais e Octais As vezes é mais facil usar um sistema numérico na base 8 ou 16 em lugar de 10 (nosso sistema decimal padrao). O sistema numérico na base 8 é chamado octal e utiliza os digitos de 0 a 7. Em octal, o ntimero 10 é 0 mesmo que 8 em decimal. O sistema numérico na base 16 6 chamado hexadecimal e utiliza os digitos de 0 a9 mais as letras de A a F, que representam 10, 11, 12, 13, 14 e 15, respectiva- mente. Por exemplo, 0 mimero hexadecimal 10 é 16 em decimal. Em virtude de esses ntimeros serem usados freqiientemente, C permite especificar constantes inteiras em hexadecimal ou octal em lugar de decimal. Uma constante hexade- cimal deve consistir em um 0x seguido por uma constante na forma hexadecimal. Uma constante octa] comega com 0. Aqui estéo alguns exemplos: int hex = 0x80; /* 128 em decimal */ int oct = 012; 7* 10 em decimal */ 38 C~ Completo e Total Cap. 2 Constantes String C suporta outro tipo de constante: a string. Uma string é um conjunto de carac- teres colocado entre aspas duplas. Por exemplo, “isso é um teste” é uma string. Vocé viu exemplos de strings em alguns dos comandos printf() dos programas de exemplo. Embora C permita que vocé defina constantes string, ela nde possui formalmente um tipo de dado string. Vocé nao deve confundir strings com caracteres. Uma constante de um Unico caractere 6 colocada entre aspas simples, como em “a”. Contudo, “a” é uma string contendo apenas uma letra. Constantes Caractere de Barra Invertida Colocar entre aspas simples todas as constantes tipo caractere funciona para a maioria dos caracteres imprimiveis. Uns poucos, porém, como 0 retorno de carro (CR), sao impossiveis de inserir pelo teclado. Por essa razo, C criou as constantes especiais de caractere de barra invertida. C suporta diversos cédigos de barra invertida (listados na Tabela 2.2) de forma que vocé pode facilmente entrar esses caracteres especiais como cons- tantes. Vocé deve usar os cédigos de barra invertida em lugar de seus ASCII equivalentes para aumentar a portabilidade. Tabela 2.2. Cédigos de barra invertida, | |) Cédigo ignificado \b Retrocesso (BS) \F Alimentacao de formulério (FF) \n Nova linha (LF) \r Retorno de carro (CR) \t Tabulacao horizontal (HT) \" Aspas duplas \' Aspas simples \o Nulo \\ Barra invertida Ww Tabulacao vertical \a Alerta (beep) \N Constante octal (onde N é uma consiante octal) \xN Constante hexadecimal (onde N é uma constante hexadecimal) Por exemplo, o programa seguinte envia a tela um caractere de nova linha e uma tabulagdo e, em seguida, escreve a string isso é um teste. Cap. 2 Expresses em C 39 #include void main(void) t£("\n\tIsso é um teste"); a Operadores C € muito rica em operadores internos. (Na realidade, C dé mais énfase aos operadores que a maioria das outras linguagens de computador.) C define quatro classes de operadores: aritméticos, relacionais, légicos e bit a bit. Além disso, C tem alguns operadores especiais para tarefas particulares. O Operador de Atribuigao Em C, vocé pode usar 0 operador de atribuigdo dentro de qualquer expressio valida de C. Isso nao acontece na maioria das linguagens de computador (in- cluindo Pascal, BASIC e FORTRAN), que tratam os operadores de atribuigio como um caso especial de comando. A forma geral do operador de atribuicao é nome_da_varidvel = expressio; onde expresso pode ser tao simples como uma tinica constante ou tao complexa quanto vocé necessite. Como BASIC e FORTRAN, C usa um iinico sinal de igual para indicar atribuicao (ao contrario de Pascal e Modula-2, que usam a constru- Gao :=). O destino, ou a parte esquerda, da atribuigao deve ser uma varidvel ou um ponteiro, ndo uma fungao ou uma constante. Freqiientemente, em literaturas de C e nas mensagens de erro dos com- piladores, vocé verd esses dois termos: lualue e realue. Exposto de forma simples, um loalue 6 qualquer objeto que pode ocorrer no lado esquerdo de um comando de atribuigo. Para todos os propésitos praticos, “Ivalue” significa “variavel’. termo rvalue refere-se as expressdes do lado direito de uma atribuicao e sig- nifica simplesmeste 0 valor da expressao. ConversGo de Tipos em Atribuigées Conversdo de tipos refere-se a situagdo em que varidveis de um tipo sdo misturadas com variaveis de outro tipo. Em um comando de atribuigao, a regra de conversao de tipos 6 muito simples: 0 valor do lado direito (o lado da expressio) de uma atribuigao é convertido no tipo do lado esquerdo (a varidvel destino), como ilus- trado por este exemplo: 0 C— Conpleto e Total Cop. int x; char ch; float £; void func (void) t ch = x; /* linha 1 */ Bae /* linha 2 */ £ = ch; y* linha 3 */ £= x; y* linha 4 */ Na linha 1, os bits mais significativos da variavel inteira x sao ignorados, dei- xando ch com os 8 bits menos significativos. Se x esta entre 256 e 0, entéo ch e x tém valores idénticos. De outra forma, o valor de ch reflete apenas os bits menos significativos de x. Na linha 2, x recebe a parte inteira de f. Na linha 3, f converte o valor inteiro de 8 bits armazenado em ch no mesmo valor em for- mato de ponto flutuante. Isso também acontece na linha 4, exceto por f converter um valor inteiro de 16 bits no formato de ponto flutuante. Quando se converte de inteiros para caracteres, inteiros longos para in- teiros ¢ inteiros para inteiros curtos, a regra basica é que a quantidade apropriada de bits significativos sera ignorada. Isso significa que 8 bits sio perdidos quando se vai de inteiro para caractere ou inteiro curto, e 16 bits si perdidos quando se vai de um inteiro longo para um inteiro, A Tabela 2.3 retine essas conversdes de tipos. Lembre-se de que a con- versao de um int em um float ou float em double etc. nao aumenta a precisao ‘ou exatidao. Esses tipos de conversio apenas mudam a forma em que 0 valor é representado, Além disso, alguns compiladores C (e processadores) sempre tra- tam uma varidvel char como positiva, nao importando que valor ela tenha quan- do é convertida para int ou float. Outros compiladores tratam valores de varidveis char maiores que 127 como ntimeros negativos. De forma geral, vocé deve usar varidveis char para caracteres e usar ints, short ints ou signed chars quando for necessario evitar um pessivel problema de portabilidade. Para utilizar a Tabela 2.3 para fazer uma conversdo nao mostrada, sim- plesmente converta um tipo por vez até acabar. Por exemplo, para converter double em int, primeiro converta double em float e, entdo, float em int. Linguagens como Pascal profbem converséo automatica de tipos. No entanto, C foi projetada para simplificar a vida do programador, permitindo que 0 trabalho seja feito em C em vez de assembler. Para substituir o assembler, C tem de permitir essas conversées de tipos. Cap. ‘ Expressbes em C 41 Tabela 2.3 ‘Conversées de tipos comuns (assumindo uma palavra de 16 bits). Tipo do destino Tipo da expressao _Possivel informagéo perdida signed char char Se valor > 127, 0 destino é negativo char short int Os 8 bits mais significativos char int Os 8 bits mais significativos char long int Os 24 bits mais significativos int long int Os 16 bits mais significativos int float A parte fraciondria e possivelmente mais float double Precisao, o resultado é arredondado © resultado € arredondado double long double Precis Atribuigdes Multiplas C permite que vocé atribua o mesmo valor a muitas varidveis usando atribuigdes miultiplas em um tnico comando. Por exemplo, esse fragmento de programa atribui a x, y e z 0 valor 0: Bx-y-e- Em programas profissionais, valores comuns sao atribuidos a varidveis usando esse método. Operadores Aritméticos A Tabela 2.4 lista os operadores aritméticos de C. Os operadores -, +, * e / tra- balham em C da mesma forma em que na maioria das outras linguagens. Eles podem ser aplicados em quase qualquer tipo de dado interno permitido em C. Quando / é aplicado a um inteiro ou caractere, qualquer resto é truncado. Por exemplo, 5/2 ser igual a 2 em uma divisdo inteira. Tabela 2.4 Operadores aritméticos. Operador — Acao - Subtracdo, também menos undrio + Adigao * Multiplicagao / Divisao % Médulo da divisao (resto) —— Decremento ++ Incremento 2 C— Completo ¢ Totat Cap. 2 O operador médulo % também trabalha em C da mesma forma que em outras linguagens, devolvendo o resto de uma divisao inteira. Contudo, % nao pode ser usado nos tipos em ponto flutuante. O seguinte fragmento de codigo ilustra %. yi x= 5; ys2: print£("%a", x/y); /* mostraré 2 */ printf (*"%d",xty); /* mostrara 1, o resto da divisdo inteira */ x=: y=2: printf("%d ta", x/y, xy); /* mostraré 0 1 */ A Ultima linha imprime 0 ¢ 1 porque 1/2 em uma divisao inteira é 0 com resto 1 © menos unério multiplica seu tinico operando por -1. Isto 6, qualquer ndmero precedido por um sinal de subtracao troca de sinal. Incremento e Decremento C inclui dois operadores titeis geralmente nao encontrados em outras linguagens. ‘Sao os operadores de incremento e decremento, ++ ¢ --. O operador ++ soma 1 ao seu operando, ¢ -- subtrai 1. Em outras palavras: @ x xn: 0 mesmo que “yo e B x= x-1; 6 0 mesmo que B x Cap. 2 Expressées em © 43 Ambos 0s operadores de incremento e decremento podem ser utilizados como prefixo ou sufixo do operando. Por exemplo: Bx =; pode ser escrito ou Cee Hé, porém, uma diferenca quando esses operadores so usados em uma expres- 4. Quando um operador de incremento ou decremento precede seu operando, C executa a operacao de incremento ou decremento antes de usar o valor do operando. Se o operador estiver apés seu operando, C usard o valor do operando antes de incrementa-lo ou decrementé-lo. O exemplo a seguir: x = 10; y = +4; coloca 11 em y. Porém, se 0 cédigo fosse es x = 10; y= xt; y receberia 10. Em ambos os casos, x recebe 11; a diferenga est4 em quando isso acontece. A maioria dos compiladores C produz cédigo-objeto para as operacdes de incremento e decremento muito rapidas e eficientes — cddigo esse que 6 melhor que aquele gerado pelo uso da sentenca de atribuigéo equivalente. Por essa razo, vocé deve usar os operadores de incremento e decremento sempre que puder. A precedéncia dos operadores aritméticos é a seguinte: Mais alta tee = (menos unario) "/% Mais baixa a Operadores do mesmo nivel de precedéncia sao avaliados pelo compilador da esquerda para a direita. Obviamente, parénteses podem ser usados para alterar a ordem de avaliagao. C trata parénteses da mesma forma que todas as outras “4 C-— Completo e Total Cap. 2 linguagens de programacdo. Parénteses forcam uma operacdo, ou um conjunto de operacées, a ter um nivel de precedéncia maior. Operadores Relacionais e Logicos No termo operador relacional, relacional refere-se as relagdes que os valores podem ter uns com os outros. No termo operador l6gico, légico refere-se as maneiras como essas relag6es podem ser conectadas. Uma vez que os operadores l6gicos e re- lacionais freqiientemente trabalham juntos, eles serao discutidos aqui em conjunto. A idéia de verdadeiro e falso é a base dos conceitos dos operadores logicos e relacionais. Em C, verdadeiro é qualquer valor diferente de zero. Falso 6 zero. As expressées que usam operadores relacionais ou légicos devolvem zero para falso e I para verdadeiro. A Tabela 2.5 mostra os operadores l6gicos ¢ relacionais. A tabela verdade dos operadores légicos é mostrada a seguir, usando 1s e¢ 0s. P q p&&q Pig 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 0 Ambos os operadores sio menores em precedéncia do que os operadores arit- méticos. Isto é, uma expressao como 10 > 1 + 12 6 avaliada como se fosse escrita 10 > (1412). O resultado é, obviamente, falso Tabela 2.5. Operadores légicos e relacionais. Operadores relacionais Operador Acao > Maior que Maior que ou igual Menor que Menor que ou igual Igual Diferente Operadores légicos Operador Acao && AND it OR ! NOT Cap.2 Expressoes em'C 45 E permitido combinar diversas operagées em uma expressio como mostrado aqui 10>5 && 110 < 9) 11 3<=4 Neste caso, o resultado é verdadeiro. Embora C nao tenha um operador légico OR exclusive (XOR), vocé pode facilmente criar uma fungao que execute essa tarefa usando os outros operadores logicos. O resultado de uma operagao XOR é verdadeiro se, e somente se, um operando (mas nao os dois) for verdadeiro. O programa seguinte contém a fun- cdo xor0, que devolve o resultado de uma operacao OR exclusivo realizada nos dois argumentos: #include int xor(int a, int b); void main (void) print£("%a", xor(1, 0)); print£("$d", xor(1, 1)); print£("$a", xor(0, 1)); print£("$d", xor(0, 0)); /* Executa uma operagaéo légica XOR usando os dois argument xor(int a, int b) ( return(a |! b) && !(a && b); } A tabela seguinte mostra a precedéncia relativa dos operadores relacionais e 16- gicos maior ! menor a Como no caso das expressées aritméticas, é possivel usar parénteses para alterar a ordem natural de avaliagéo de uma expressao relacional e/ou légica. Por exemplo, 0 && 0110 46 C— Completo e Total Cap. 2 6 falso. Porém, quando parénteses so adicionados 4 mesma expressao, como mostrado aqui, o resultado é verdadeiro: {0 && 0) £40 Lembre-se de que toda expressao relacional e légica produz como re- sultado 0 ou 1. Entao, o seguinte fragmento de programa nao apenas esta correto, como imprimiré o ntimero 1 na tela: int 3x; x = 10 printé Bd", x>10); Operadores Bit a Bit Ao contrério de muitas outras linguagens, C suporta um completo conjunto de operadores bit a bit. Uma vez que C foi projetada para substituir a linguagem assembly na maioria das tarefas de programagio, era importante que ela tivesse a habilidade de suportar muitas das operacdes que podem ser feitas em lingua- gem assembly. Operacao bit a bit refere-se a testar, atribuir ou deslocar os bits efetivos em um byte ou uma palavra, que correspondem aos tipos de dados char e int e variantes do padrao C. Operacées bit nao podem ser usadas em float, double, long double, void ou outros tipos mais complexos. A Tabela 2.6 lista 0s operadores que se aplicam as operacées bit a bit. Essas operacdes sao aplicadas aos bits individuais dos operandos. Tabela 2.6 Operadores bit a bit. Operador Acao & AND ! OR n OR exclusive (XOR) ~ Complemento de um > Deslocamento a esquerda << Deslocamento a direita As operacées bit a bit AND, OR e NOT (complemento de um) sio go- vernadas pela mesma tabela verdade de seus equivalentes ldgicos, exceto por trabalharem bit a bit. O OR exclusivo (4) tem a tabela verdade mostrada aqui: Cap. 2 Expressdes enn C "7 Pp q pra 0 0 0 1 0 1 1 1 0 0 1 1 Como a tabela indica, 0 resultado de um XOR é verdadeiro apenas se exatamente um dos operandos for verdadeiro; caso contrario, sera falso. Operagées bit a bit encontram aplicagdes mais freqiientemente em “dri- vers” de dispesitivos — como em programas de modems, rotinas de arquivos em disco e rotinas de impresoras — porque as operacées bit a bit mascaram certos bits, como o bit de paridade. (O bit de paridade confirma se o restante dos bits em um byte nao se modificaram. E geralmente o bit mais significativo em cada byte.) Imagine © operador AND como uma maneira de desligar bits. Isto é, qualquer bit que é zero, em qualquer operando, faz com que o bit correspondente no resultado seja desligado. Por exemplo, a seguinte funcao lé um caractere da porta do modem usando a funcao read_modem() e, entao, zera o bit de paridade. char get_char_from_modem(void) { char ch; ch = reaG_modem(}; /* 18 um caractere do modem */ urn (ch & 127); } A paridade é indicada pelo oitavo bit, que é colocado em 0, fazendo-se um AND com um byte em que os bits de 1 a 7 so 1 o bit 8 é 0. A expressao ch & 127 significa fazer um AND bit a bit de ch com os bits que compdem 0 ntimero 127. O resultado é que 9 oitavo bit de ch esta zerado. No seguinte exemplo, assuma que ch tenha recebido 0 caractere “A” e que o bit de paridade tenha sido ativado. Bit de paridade | 4 11000001 ch contém “A” com a paridade ligada 01111111 127 em bindrio & —————__ faz AND bit a bit 01000001 “A” sem paridade 46 C — Completo e Total — : Cap. 2 © operador OR, ao contrario de AND, pode ser usado para ligar um bit. Qualquer bit que é 1, em qualquer operando, faz com que o bit correspondente no resultado seja ligado. Por exemplo, o seguinte mostra a operagio 128 | 3: 000000 128 em binario 00017 3 em binario i OR bit a bit 10000011 resultado Um OR exclusivo, normalmente abreviado por XOR, ativa um bit se, e somente se, os bits comparados forem diferentes. Por exemplo, 1274120 & 01111111 127embinario 01111000 120 em binario A —_—_—_— XOR bit a bit 00000111 _ resultado Lembre-se de que os operadores légicos e relacionais sempre produzem um resultado que é 1 ou 0, enquanto as operagées similares bit a bit produzem quaisquer valores arbitrarios de acordo com a operacio especifica. Em outras palavras, operagées. bit a bit podem possuir valores diferentes de 0 e 1, mas os operadores légicos sempre conduzem a 0 ou 1. Os operadores de deslocamento, >> e <<, movem todos os bits de uma varidvel para a direita ou para a esquerda, como especificado. A forma geral do comando de deslocamento a direita é varidvel >> mimero de posigées de bits A forma geral do comando de deslocamento a esquerda é varidvel << nimero de posigdes de bits Conforme os bits s4o deslocados para uma extremidade, zeros sao co- locados na outra. Lembre-se de que um deslocamento ndo é uma rotagao. Ou seja, os bits que saem por uma extremidade nao voltam para a outra. Os bits deslocados sao perdidos e zeros sao colocados. Operagdes de deslocamento de bits podem ser uiteis quando se decodi- fica a entrada de um dispositivo externo, como um conversor D/A, e quando se léem informagées de estado. Os operadores de desiocamento em nivel de bits. também podem multiplicar e dividir inteiros rapidamente. Um deslocamento a direita efetivamente multiplica um namero por 2 e um deslocamento a esquerda divide-o por 2, como mostrado na Tabela 2.7. O programa seguinte ilustra os operadores de deslocamento. Cap. 2 “-Expresstes em © : 0 Tabela 2.7 Multiplicagao e divisdo com operadores de deslocamento. | unsigned char x; x a cada execugao da sentenga —-Vallor de x x=7; 00000111 7 00001110 14 01110000 112 11000000 192 01100000 96 00011000 24 Cada deslocamento a esquerda multiplica por 2. Note que se perdeu informagio apés 0 x<<2 porque um bit foi deslocado para fora Cada deslocamento a direita divide por 2. Note que divisdes subseqiientes nao trazem de volta bits anteriormente perdidos. /* Um exemplo de deslocamento de bits. */ #include void main(void) { unsigned int i; int 3; isd; /* deslocamentos 4 esquerda */ for(j=0; j<4; j+*) { i=i<<1; /* desioca i de 1 4 esquerda, que é 0 mesmo que multiplicar por 2 */ printf ("deslocamento & esquerda %d: d\n", 3, i); } /* deslocamentos a direita ‘/ for (j=0; j> 1; /* desloca i de 1 & direita, que é 0 mesmo que dividir por 2 */ print£(*deslocamento a direita td:%d\n", j, i); ) ) O operador de complemento a um, ~, inverte 0 estado de cada bit da variavel especificada. Ou seja, todos os 1s s0 colocados em 0 € todos os 0s sa0 colocados em I. 50 C— Completo'é Total Cap.2 Os operadores bit a bit sio usados freqiientemente em rotinas de crip- tografia. Se vocé deseja fazer um arquivo em disco parecer ilegivel, realize algu- mas manipulacées bit a bit nele. Um dos métodos mais simples é complementar cada byte usando o complemento de um para inverter cada bit no byte, como mostrado aqui: Byte original 00101100 Apos 0 12 complemento. 11010011 ean Apés 0 22complemento 00101100 Note que uma seqiiéncia de dois complementos produz 0 nimero ori- ginal. Logo, 0 primeiro complemento representa a versio codificada de cada byte. O segundo complemento decodifica-o ao seu valor original Vocé poderia usar a fungdo encode(), mostrada aqui, para codificar um caractere. /* Uma fungéo simples de criptografia. */ char encode(char ch) return(~ch); /* complementa */ O Operador ? C contém um operador muito poderoso e conveniente que substitui certas sen- tencas da forma if-then-else. O operador ternario ? tem a forma geral Expl ? Exp2 : Exp3; onde Expl, Exp2 e Exp3 sao expressdes. Note 0 uso e 0 posicionamento dos dois- pontos. O operador ? funciona desta forma: Exp! € avaliada. Se ela for verda- deira, entao Exp2 é avaliada e se toma o valor da expresso. Se Expl é falsa, entao Exp3 é avaliada e se torna o valor da expressao. Por exemplo, em x = 10; y = x29 7 100 : 200; ay é atribuido 0 valor 100. Se x fosse menor que 9, y teria recebido o valor 200 O mesmo cédigo, usando 0 comando if-else, é Cap. 2 Exprressoes eit C St x = 10; if (x29) y = 100 else y = 200; O operador ? sera discutido mais completamente no Capitulo 3 com relagao as outras sentengas condicionais de C. Os Operadores de Ponteiros & e * Um ponteiro é um endereco na memoria de uma variavel. Uma varidvel de ponteiro é uma variavel especialmente declarada para guardar um ponteiro para seu tipo especificado. Saber 0 endereco de uma variavel pode ser de grande ajuda em certos tipos de rotinas. Contudo, ponteiros tém trés fungdes principais em C. Eles podem fornecer uma maneira rapida de referenciar elementos de uma ma- triz. Os ponteiros também permitem que as fungdes em C modifiquem seus pa- rametros de chamada. Por ultimo, eles suportam listas encadeadas e outras es- truturas dinamicas de dados. O Capitulo 5 é dirigido exclusivamente a ponteiros. Porém, esse capitulo aborda de forma breve os dois operadores que sao usados para manipular ponteiros. O primeiro operador de ponteiro é &. Ele 6 um operador unario que devolve 0 endereco na memoria de seu operando. (Lembre-se de que um ope- rador unério requer apenas um operando.) Por exemplo, poe o enderego na meméria da variavel count em m. Esse endereco é a posicao interna da varidvel no computador. Ele nao tem nenhuma relacéo com 0 valor de count. Vocé pode imaginar & como significando “o endereco de”. Desta for- ma, a sentenca de atribuicao anterior significa “m recebe o endereco de count”. acount; Para entender melhor essa atribuicdo, assuma que a varidvel count usa a posigao de meméria 2000 para armazenar seu valor. Também assuma que count tem o valor 100. Entao, apés a atribuicdo anterior, m tem o valor 2000. O segundo operador é *, que é 0 complemento de &. O * 6 um operador unério que devolve o valor da varidvel localizada no endereco que 0 segue. Por exemplo, se m contém 0 endereco da variavel count, 52 C— Completo e Total Cap. 2 Boc-en coloca 0 valor de count em q. Agora q tem o valor 100 porque 100 est4 arma- zenado na posicao 2000, 0 endereco na memoria que esta armazenado em m Pense no * como significando “no enderego de”. Neste caso, a sentenga poderia ser lida como “q recebe o valor do endereco de m’. Infelizmente, 0 simbolo de multiplicacao e 0 simbolo de “no enderego de” sao iguais, e o simbolo para o AND bit a bit e 0 simbolo de “o enderego de” também sao iguais. Esses operadores nao tém nenhuma relacéo um com 0 outro. Ambos, & e *, tem uma precedéncia maior que todos os operadores arit- méticos, exceto 0 menos unério, que tem a mesma precedéncia. Variaveis que guardam ponteiros devem ser declaradas como tal. Va- ridveis que armazenam enderecos da meméria, ou ponteiros, como sao chamados em C, devem ser declarados colocando-se * em frente ao nome da varidvel para indicar ao compilador que ela guardara um ponteiro para aquele tipo de variavel Por exemplo, para declarar uma varidvel ponteiro ch para char, escreva char *ch; Aqui, ch nao é um caractere, mas um ponteiro para caractere — ha uma grande diferenca. O tipo de dado que o ponteiro aponta, neste caso char, é chamado o tipo base do ponteiro. De qualquer forma, a varidvel ponteiro é uma variavel que mantém o endereco de um objeto do tipo base. Logo, um ponteiro para caractere (ou qualquer ponteiro) é de tamanho suficiente pata guardar um enderego como definido pela arquitetura do computador em que esté rodando. Lembre-se de que um ponteiro deve ser usado apenas para apontar para dados que sao do tipo base do ponteiro. Vocé pode misturar diretivas de ponteiro ¢ de nao-ponteiros na mesma declaragao. Por exemplo @ int x, *y, count; declara x e count como sendo do tipo inteiro e y como um ponteiro para o tipo inteiro. Os seguintes operadores * e & poem o valor 10 na variével chamada target. Como esperado, esse programa mostra o valor 10 na tela. Cap.2 Expressiies em C 53 #include void main(void) { int target, source; int *m target); O Operador em Tempo de Compilagdao sizeof O operador sizeof é um operador em tempo de compilacao unério que retorna © tamanho, em bytes, da varidvel ou especificador de tipo, em parénteses, que ele precede. Por exemplo, assumindo que inteiros sio de 2 bytes e que floats sao de 8 bytes, float £; printf ("tf", sizeof f); printf ("%a", sizeof (int)); ir mostrar na tela 8 2. Lembre-se de que para calcular 0 tamanho de um tipo, o nome do tipo deve ser colocado entre parénteses. Isso nao é necessério para nomes de varidveis, embora nao haja qualquer mal em fazé-lo. O padrao ANSI (usando typedef) define um tipo especial chamado size_t, que corresponde de forma imprecisa a um inteiro sem sinal. Tecnicamente, 0 valor devolvido por sizeof é do tipo size_t. Para todos os fins praticos, porém, vocé pode imagind-lo (e us4-lo) como se fosse um valor sem sinal. sizeof ajuda basicamente a gerar cdigos portaveis que dependam do tamanho dos tipos de dados internos de C. Por exemplo, imagine um programa de banco de dados que precise armazenar seis valores inteiros por registro. Se vocé quer transportar 0 programa de banco de dados para varios computa- dores, nao deve assumir o tamanho de um inteiro, mas deve determinar 0 ta- manho real do inteiro usando sizeof. Sendo esse 0 caso, vocé poderia usar a seguinte rotina para escrever um registro em um arquivo em disco: a C— Campleto ¢ Total Cap. 2 /* Escreve 6 ij void put_rec (in { int len; iros em um arquivo em disco. */ rec[6], FILE *fp) len = rite(rec, sizeof rec, 1, fp); if(len != 1) printf("erro de escrita"); } Codificada como mostrado, put_rec() compila e roda corretamente em qualquer computador, nao importando quantos bytes tenha um inteiro. O Operador Virgula O operador virgula é usado para encadear diversas expressdes. O lado esquerdo de um operador virgula é sempre avaliado como void. Isso significa que a ex- pressio do lado direito torna-se valor de toda a expressao separada por vir gulas. Por exemplo, x = (y=3, y+); primeiro atribui 0 valor 3 a y e, em seguida, atribui o valor 4 a x. Os parénteses sA0 necessdrios porque o operador virgula tem uma precedéncia menor que o operador de atribuicao. Essencialmente, a virgula provoca uma seqiiéncia de operagdes. Quando ela é usada do lado direito de uma sentenca de atribuicao, o valor atribuido é © valor da tiltima expressao da lista separada por virgulas. O operador virgula tem, de certa forma, 0 mesmo significado da palavra e em portugués normal, como na frase “faca isso e isso e isso”. Os Operadores Ponto (.) e Seta (->) Os operadores . (ponto) e -> (seta) referenciam elementos individuais de estru- turas e unides. Estruturas e unides sao tipos de dados compostos que podem ser referenciados segundo um tinico nome (veja o Capitulo 7). O operador ponto é usado quando se esta referenciando a estrutura ou uniao real. O operador seta é usado quando um ponteiro para uma estrutura é usado. Por exemplo, dada a estrutura global struct employee t char name (80); Cap. 2 Expressbes em C 55 int age; float wage; 3} emp; struct employee *p = kemp; /* enderego de emp em p */ vocé escreveria o seguinte cédigo para atribuir o valor 123.23 ao elemento wage da estrutura emp: WB oemp.wage = 123.23; No entanto, a mesma atribuigao, usando um ponteiro para emp, seria @ p->wage = 123.23; Parénteses e Colchetes Como Operadores Em C, parénteses so operadores que aumentam a precedéncia das operagdes dentro deles. Colchetes realizam indexagao de matrizes (eles serao discutidos no Ca- pitulo 4). Dada uma matriz, a expresso dentro de colchetes prové um indice dentro dessa matriz. Por exemplo: #include char s(80); void main(void) { s(3) = °K; printf ("tc", s(3]}; y Esse cédigo primeiro atribui o valor ’X’ ao quarto elemento (lembre-se de que todas as matrizes em C comegam em 0) da matriz s e imprime esse elemento. Resumo das Precedéncias A Tabela 28 lista a precedéncia de todos os operadores de C. Note que todos os operadores, exceto os operadores undrios e ?, associam da esquerda para a direita. Os operadores unérios (*, & e -) e ? associam da direita para a esquerda 56 ‘C— Completa e Total Cap. 2 Tabela 2.8 A precedéncia dos operadores em C. Maior ous +f eae == = tipo) * & sizeof /= ete. Menor a Expressoes Operadores, constantes e variaveis sio os elementos que constituem as expres- ies. Uma expresso em C é qualquer combinacao valida desses elementos. Uma vez que a maioria das expressdes tende a seguir as regras gerais da algebra, elas sao freqiientemente tomadas como certas. Contudo, existem uns poucos aspectos de expressdes que se referem especificamente a C. Ordem de Avaliacao O padrao C ANSI nao estipula que as subexpressdes de uma expressio devam ser avaliadas em uma ordem especificada. Isso deixa 0 compilador livre para rearranjar uma expressao para produzir o melhor cédigo. No entanto, isso tam- bém significa que seu cédigo nunca deve contar com a ordem em que as subex- pressées so avaliadas. Por exemplo, a expressao B® x= f10 + 220; nao garante que f1() sera chamada antes de £20. Cap. 2 Expressies an C 57 Conversdo de Tipos em Expressées Quando constantes e varidveis de tipos diferentes so misturadas em uma expressio, elas sao convertidas a um mesmo tipo. O compilador C converte todos os operandos no tipo do maior operando, 0 que é denominado promogio de tipo. Isso é feito ope- Tago por operacao, como descrito nas regras de conversdo de tipos abaixo. SE um operando é long double ENTAO 0 segundo é convertido para long double SENAO, SE um operando é double ENTAO 0 segundo é convertido para double SENAO, SE um operando é float ENTAO 0 segundo é¢ convertido para float SENAO, SE um operando é unsigned long ENTAO o segundo é convertido para unsigned long SENAO, SE um operando é long ENTAO o segundo é convertido para long, SENAO, SE um operando é unsigned int ENTAO 0 segundo é convertido para unsigned int Ha ainda um caso adicional especial: se um operando é long e 0 outro é unsigned int, e se o valor do unsigned int nao pode ser representado por um long, os dois operandos sao convertidos para unsigned long. Uma vez que essas regras de conversao tenham sido aplicadas, cada par de operandos é do mesmo tipo e o resultado de cada operagao é do mesmo tipo de ambos 0s operandos. Por exemplo, considere as conversées de tipo que ocorrem na Figura 2.3. Primeiro, o caratere ch é convertido para um inteiro e float f é convertido para double. Em seguida, o resultado de ch/i 6 convertido para double porque f*d é double. O resultado final é double porque, nesse momento, os dois operandos so double. Casts Vocé pode forcar uma expressao a set de um determinado tipo usando um cast. A forma genérica de um cast é (tipo) expressao onde tipo é qualquer tipo de dados valido em C. Por exemplo, para garantir que a expresso x/2 resulte em um valor do tipo float, escreva BB (float) x/2; 5B © — Completo ¢ Total Cap. 2 char ch; int i; float f; double d; result = (ch/i) + (fd) - (fi); int | double float int double float double Figura 2.3. Um exemplo de conversio dé tipo. Casts so operadores tecnicamente. Como operador, um cast é undrio e possui a mesma precedéncia que qualquer outro operador unério. Embora os casts ndo sejam muito usados em programaao, eles podem ser muito titeis quando necessédrios. Por exemplo, suponha que vocé deseje usar um inteiro para controlar uma repeticao, no entanto as operagées sobre o valor exigem uma parte fraciondria, como no programa seguinte: #include void main(void) /* imprime i e i/2 com fracgdes */ ‘ int i; for (isl; i<=100; ++i) print£("@d / 2 é: ®f\n", i, (float) i /2); Sem o cast (float), teria sido efetuada somente uma divisao inteira. O cast garante que a parte fraciondria do resultado seja exibida. Cap. 2 Expressbés em C 59 Espacgamento e Parénteses Vocé pode acrescentar tabulacées e espacos a expresses em C para torné-las mais legiveis. Por exemplo, as duas proximas expressdes si0 a mesma x=l0/y ~ (127/x); x= 10 / y ~ (127/x); Parénteses redundantes ou adicionais ndo causam erros nem diminuem a velocidade de execucao da expressao. Voce deve usar parénteses para esclarecer a ordem de avaliacao, tanto para vocé mesmo como para os demais. Por exemplo, quais das duas expressoes a seguir 6 mais facil de ler? x=y/2-34*tempa127; x = (y/3) - ((34*temp) &127); C Reduzido Existe uma variante do comando de atribuigao, as vezes chamada de C reduzido, que simplifica a codificagao de um certo tipo de operagées de atribuicao. Por exemplo, Box = x10; pode ser escrito Bx += 10; © par operador += diz ao compilador para atribuir a x o valor de x mais 10. Essas abreviacdes existem para todos os operadores binérios em C (aque- les que requerem dois operands). A forma geral de uma abreviacéo C como var = rar operador expressiio é 0 mesmo que var operador = expresso Considere um outro exemplo: 60 C= Completo e Total Cap. 2 B x = x-100; 0 mesmo que Wx = 100; Vocé verd a notagao abreviada sendo utilizada largamente em programas escritos profissionalmente em C; vocé deve familiarizar-se com ela. ar Comandos de Controle do Programa Este capitulo discute os ricos e variados comandos de controle do programa em C. O padsao ANSI divide os comandos de C nestes grupos: m Selecao Iteragao Desvio Rétulo Expresso Bloco Esto inclufdos nos comando de selesao if e switch. (O termo “comando condicional” € freqiientemente usado em lugar de “comando de selecéo”. No entanto, 0 padrao ANSI usa “selecdo”, como também este livro.) Os comandos de iteracdo sdo while, for e do-while. Sao também normalmente chamados de comandos de laco. Os comandos de salto ou desvio so break, continue, goto e return. Os comandos de rétulo sao case e default (discutidos juntamente com 0 comando switch) e 0 comando label (discutido com goto). Sentencas de expres- so so aquelas compostas por uma expressdo C valida. Sentengas de bloco sao simplesmente blocos de cédigo. (Lembre-se de que um bloco comega com um [ e termina com um |.) Como muitos comandos em C contam com a saida de alguns testes con- dicionais, comecaremos revendo os conceitos de verdadeiro e falso em C. or 62 C— Completo e Total Cap. 3 Wi Verdadeiro e Falso em C Muitos comandos em C contam com um teste condicional que determina 0 curso da aio. Uma expressao condicional chega a um valor verdadeiro ou falso. Em C, ao contrario de muitas outras linguagens, um valor verdadeiro é qualquer valor diferente de zero, incluindo ntimeros negativos. Um valor falso é 0. Esse método para verdadeiro e falso permite que uma ampla gama de rotinas sejam codificadas de forma extremamente eficiente, como vocé vera em breve. HZ Comandos de Selegao C suporta dois tipos de comandos de selegao: if e switch. Além disso, o operador ? 6 uma alternativa ao if em certas circunstancias. if A forma geral da sentenca if é if (expressio) comando; else comando; onde comando pode ser um Unico comando, um bloco de comandos ou nada (no caso de comandos vazios). A clausula else ¢ opcional. Se a expressiio 6 verdadeira (algo diferente de 0), 0 comando ou bloco que forma 0 corpo do if é executado; caso contrario, 0 comando ou bloco que é © corpo do else (se existir) é executado. Lembre-se de que apenas 0 c6digo as- sociado ao if ou 0 c6digo associado ao else ser executado, nunca ambos. O comando condicional controlando o if deve produzir um resultado escalar. Um escalar é um inteiro, um caractere ou tipo de ponto flutuante. No entanto, é raro usar um ntimero em ponto flutuante para controlar um comando condicional, porque isso diminui consideravelmente a velocidade de execucao. (A CPU executa diversas instrugdes para efetuar uma operagao em ponto flu- tuante. Ela usa relativamente poucas instrucdes para efetuar uma operacao com caractere ou inteiro.) Por exemplo, considere o programa a seguir, que é uma versio muito simples do jogo de adivinhar o “ntimero magico”. Ele imprime a mensagem “** Certo **” quando 0 jogador acerta o mimero magico. Ele produz o numero mé- gico usando o gerador de ntimeros randémicos de C, que devolve um nimero arbitrario entre 0 e RAND-MAX (que define um valor inteiro que é 32.767 ou maior) exige o arquivo de cabecalho stdlib.h. Cap. 3 Comandos de controle do programa 63 /* Programa de ntimeros magicos #1. */ #include #include void main(void) £ int magic; /* mimero magico */ int guess; /* palpite do usudrio */ magic = rand(); /* gera o mimero magico */ printf (*adivinhe o nimero magico: "); scanf("$d", &guess) ; if (guess == magic) printf£("** Certo **"); } Levando o programa do niimero magico adiante, a préxima versao ilustfa 0 uso da sentenca else para imprimir outra mensagem em resposta a um numero er- rado. /* Programa de niimeros mdgicos #2. */ #include #include void main(void) i int magic; /* niimero mdgico */ int guess; /* palpite do usuério */ magic = rand(); /* gera o nimero magico */ printf("adivinhe o ntimero magico: "); scanf("$d", &guess); if(guess == magic) printf£("** Certo **"); else print£(*Errado"); ifs Aninhados Um if aninhado é um comando if que é 0 objeto de outro if ou else. ifs aninhados sdo muito comuns em programacao. Em C, um comando else sempre se refere 64 C— Completo e Total i Cap. 3 a0 comando if mais préximo, que esta dentro do mesmo bloco do else ¢ nao estd associado a outro if, Por exemplo if (i) ( if(j) comando 1; if(_\) comando 2; /* este if */ else comando 3; /* esté associado a este else */ } else comando 4; /* associado a if(i) */ Como observado, o ultimo else nao esta associado a iffj) porque nao pertence ao mesmo bloco. Em vez disso, 0 ultimo else esta associado ao if(i). O else interno esta associado ao iftk), que é 0 if mais préximo. © padrao C ANSI especifica que pelo menos 15 niveis de aninhamento devem ser suportados. Na pratica, a maioria dos compiladores permite substan- cialmente mais. Vocé pode usar um if aninhado para melhorar o programa do numero magico dando ao jogador uma realimentacao sobre um palpite errado. /* Programa de numeros magicos #3. */ #include #include void main (void) ( int magi int guess; /* mimero magico */ /* palpite do usudrio */ magic = rand(); /* gera o numero magico */ print£("Adivinhe o nimero mdgico: "); scanf("#d", &guess); if (guess magic) { print£("** Certo ***); print£(" %d 6 0 mimero mégico\n", magic); } else ( printf ("Errado, *); if(guess > magic) print£("muito alto\n"); else printf (*muito baixo\n"); } Cap. 3 ‘Comanitos de controle do programa. 3 65 A Escada if-else-if Uma construgdo comum em programacao é a forma if-else-if, algumas vezes cha- mada de escada if-else-if devido a sua aparéncia. A sua forma geral é if(expressao)comando; else if(expressiio)comando; else if(expressao)comando; else comando; As condigées sao avaliadas de cima para baixo. Assim que uma condicdo ver- dadeira é encontrada, 0 comando associado a ela é executado e desvia do resto da escada. Se nenhuma das condigées for verdadeira, entao 0 tiltime else € exe- cutado. Isto é, se todos os outros testes condicionais falham, o ultimo comando else é efetuado. Se o tiltimo else nao esta presente, nenhuma agio ocorre se todas as condigdes sao falsas Embora seja tecnicamente correta, 0 recuo da escada if-else-if anterior pode ser excessivamente profundo. Por essa razdo, a escada if-else-if é geralmente recuada desta forma: iflexpressio) comando; else if(expressdo) comando; else iffexpressao) comando; else comando; Usando uma escada if-else-if, 0 programa do ntimero magico torna-se: /* Programa de nimeros magicos #4. */ #include #include void main(void) 66 C— Conipleto e Tota Cap. 3 int magic; /* mimero m4gico */ int guess; /* palpite do usudrio */ magic = rand(); /* gera o mimero magico */ printf ("Adivinhe o mimero magico: "); "Sd", &guess); magic) ( ** Certo ***); printf ("8d é 0 numero magico", magic); se if (guess > magic) rintf("Errado, muito alto"); else printf("Errado, muito baixo"); O ? Alternativo Vocé pode usar 0 operador ? para substituir comandos if-else na forma geral: if(condigio) expresso; else expressiio; Contudo, os corpos de if e else devem ser uma expressao simples — nunca um outro comando de C. © 26 chamado de um operador terndrio porque ele requer trés operandos. Ele tem a seguinte forma geral Expl ? Exp2 : Exp3 onde Expl, Exp2 e Exp3 sao expressées. Note 0 uso e 0 posicionamento dos dois- pontos. © valor de uma expressdo ? é determinada como segue: Exp] 6 avaliada. Se for verdadeira, Exp? sera avaliada e se tornard o valor da expressao ? inteira Se Expl é falsa, entio Exp3 é avaliada e se torna o valor da expressao. Por exem- plo, considere x = 10; y = x>9 ? 100 : 200; Cap. 3 ‘Comandos de.controle do programa 67 Nesse exemplo, 0 valor 100 é atribuido a y. Se x fosse menor que 9, y teria recebido o valor 200. O mesmo cédigo escrito com 0 comando if-else seria x = 10; if (@9) y = 100; else y = 200; O seguinte programa usa 0 operador ? para elevar ao quadrado um valor inteiro digitado pelo usuario. Contudo, este programa preserva 0 sinal (10 ao quadrado € 100 e -10 ao quadrado é -100). #include void main(void) { int isqrd, print£("Digite um numero: scanf("td", &i); isqrd = in0 2 itd: (iti); print£("%d ao quadrado é $a", i, isard); O uso do operador ? para substituir comandos if-else nao é restrito a atribui apenas. Lembre-se de que todas as fung6es (exceto aquelas declaradas como void) podem retornar um valor. Logo, vocé pode usar uma ou mais chamadas a fun- GOes em uma expresso em C. Quando o nome da fungdo 6 encontrado, a funcao € executada e, entao, seu valor de retorno pode ser determinado. Portanto, vocé pode executar uma ou mais chamadas a fungdes usando o operador ?, colocando as chamadas nas expresses que formam os operandos, como em #include int f1(ini int £2(void); void main(void) { int t; printf("Digite um numero: ");

Você também pode gostar