Вы находитесь на странице: 1из 97

ProgramaçãoProgramaçãoProgramaçãoProgramação BásicaBásicaBásicaBásica emememem CCCC

SUMÁRIO

SUMÁRIO

 

2

1 INTRODUÇÃO

6

1.1 Um Breve Histórico da Linguagem C

6

1.2 Por que C?

 

7

1.3 Um Pouco de Terminologia

8

1.4 O Que é um Compilador?

9

2 O MUNDO “UNIX” LIKE

 

11

2.1 Comando de Auxílio

11

2.2 Comandos de Navegação e Controle de Diretórios

12

2.3 Comandos de Manutenção de Arquivos

13

2.4 Recursos do Sistema

13

2.5 Impressão de Arquivos

14

2.6 Comandos Diversos

 

14

3 GNU gcc

 

15

3.1 Especificando o Arquivo de Saída

15

3.2 Somente Compilar, Não Gerar Arquivo Executável

15

3.3 Solicitando uma Compilação com Verificação Completa de Erros

15

3.4 Biblioteca Matemática

15

3.5 Gerando Informações de Depuração

16

3.6 Outras Opções ?! Lembre-se Sempre do man

17

3.7 Outros Compiladores

17

4 A ANATOMIA DE UM PROGRAMA EM LINGUAGEM C

 

19

5 O

PRÉ-PROCESSADOR C

20

5.1 Definir Constantes Simbólicas: #define

20

5.2 Cancelar uma Definição Simbólica: #undef

20

5.3 Inclusão de Arquivos: #include

21

5.4 Contato Imediato com C

21

 

5.4.1 Primeiro

Programa

21

5.4.2 Segundo

Programa

23

6 TIPOS, OPERADORES E EXPRESSÕES

 

24

6.1 Identificadores

24

6.2 Tipos de Dados

24

6.3 O Que São Variáveis?

25

6.4 Criando Variáveis Imutáveis (As Constantes)

26

6.5 Classes de Armazenamento e Escopo das Variáveis

27

6.6 Conversão Momentânea de Tipos (Casts)

29

7

ENTRADA E SAÍDA

32

7.1 Entrada e Saída de Caracteres

32

7.2 Entrada e Saída de Cadeias de Caracteres (Strings)

33

7.3 Entrada e Saída Formatada de Dados

34

7.3.1 A Função de Entrada Formatada scanf

34

7.3.2 A Função de Saída Formatada printf

36

8 COMANDOS DE CONTROLE DE FLUXO

 

41

8.1 Comando if

 

41

8.2 Comando if-else

41

8.3 Comando switch

42

8.4 Comando for

44

8.5 Comando while

45

8.6 Comando do-while

46

8.7 Comando break

 

46

8.8 Comando continue

47

8.9 Comando goto

 

47

9 MATRIZES, STRINGS, PONTEIROS E SIZEOF( )

 

49

9.1 Matrizes (Arrays)

 

49

9.2 Cadeias de Caracteres (Strings)

50

9.3 Ponteiros

 

51

9.4 Operadores Utilizados com Ponteiros

52

9.5 Aritmética de Ponteiros

54

9.6 Ponteiros Constantes para char

55

9.7 O Operador sizeof( )

56

10 ALOCAÇÃO

DINÂMICA DE MEMÓRIA

57

10.1 Alocação de Memória

58

10.2 Liberação da Memória

58

11 FUNÇÕES

 

59

11.1 Anatomia de uma Função

59

11.2 Protótipos de Função

60

11.3 A Passagem de Parâmetro(s) para as Funções

60

 

11.3.1 Passagem “por valor”

60

11.3.2 Passagem “por referência”

61

11.3.3 Matrizes Passadas para Funções

62

11.4 Recursividade

 

63

11.5 Ponteiros para Funções

64

12 TIPOS DE DADOS COMPLEXOS OU DEFINIDOS PELO USUÁRIO

 

66

12.1

Estruturas

66

12.1.1 Ponteiros para

Estruturas

68

12.1.2 Operadores de

Seleção

69

12.1.3 Estruturas Aninhadas

70

12.1.4 Matrizes de Estruturas

71

12.1.5 Passando Estruturas para Funções

71

12.2

Estrutura de Campos de Bit

72

12.3 Uniões

73

12.4 Enumerações

74

12.5 Definição de Novos Tipos

77

13 ARQUIVOS

79

13.1 Funções Básicas Para Manipular Arquivos

80

13.1.1 Abrir Arquivo: fopen()

80

13.1.2 Fechar

um Determinado Arquivo: fclose()

81

13.1.3 Fechar Todos os Arquivos Abertos: fcloseall()

81

13.1.4 Limpar ou Descarregar o Buffer de um Arquivo: fflush()

81

13.1.5 Limpar ou Descarregar Todos os Buffers de Arquivos: fflushall()

81

13.1.6 Detectar o Final de um Arquivo: feof()

82

13.1.7 Reposicionar o Ponteiro de um Arquivo: fseek()

82

13.2 Funções Básicas para Entrada e Saída em Arquivos Texto

82

13.2.1 Ler um Caractere de um Arquivo: fgetc() ou getc()

82

13.2.2 Escrever um Caractere de um Arquivo: fput() ou putc()

83

13.2.3 Ler uma Seqüência de Caracteres de um Arquivo: fgets()

83

13.2.4 Escrever uma Seqüência de Caracteres de um Arquivo: fputs()

83

13.2.5 Ler Dados Formatados de Arquivo: fscanf()

83

13.2.6 Escrever Dados Formatados em Arquivo: fprintf()

84

13.3 Funções Básicas para Entrada e Saída em Arquivos Binários

84

13.3.1 Ler uma Seqüência de Bytes de um Arquivo: fread()

84

13.3.2 Escrever uma Seqüência de Bytes em um Arquivo: fwrite()

84

13.4 Funções de Tratamento de Erros

85

13.4.1 Limpar Indicadores de Erro e de Fim de Arquivo: clearerr()

85

13.4.2 Verificando a Ocorrência de Erros: ferror()

85

13.4.3 Escreve Mensagem de Erro na Saída Padrão: perror()

85

13.4.4 Descobrir Texto da Mensagem de Erro Relativa a um Código: strerror()

86

13.4.5 Exemplo de Código Tratando Erro

86

14 EXERCÍCIOS

87

14.1 Seqüenciais:

87

14.2 Condicionais

88

14.3 Repetição:

89

15 ALGUMAS FUNÇÕES ÚTEIS

 

91

15.1 Funções de Controle de Fluxo

91

15.2 Funções de Conversão de ASCII para Binário

91

15.3 Funções de Conversão de Binário para ASCII

92

15.4 Funções de Gerenciamento de Memória

92

15.5 Funções de Ambiente

92

15.6 Funções de Números Aleatórios

92

15.7 Funções Relacionadas com Tempos e Datas

92

15.8 Funções Manipuladoras de Strings

93

15.9 Funções de Buffer

94

15.10 Funções Matemáticas

95

REFERÊNCIA BIBLIOGRÁFICA

 

97

1

INTRODUÇÃO

Seja bem-vindo ao mundo do C. Este capítulo irá prepará-lo para o aprendizado e a utilização desta poderosa, e cada vez mais popular, linguagem de programação.

Mas e o que você necessita para começar?

Bom, em primeiro lugar você precisa estar motivado, estar interessado. Mais do que você já está; por isto lhe apresentaremos nos próximos parágrafos alguns dos aspectos mais atraentes desta linguagem.

Segundo: você precisa de um guia. Esta apostila será uma base para tal, mas é sempre recomendável ter outras referências para aqueles momentos confusos.

Depois, você precisa ter acesso a um equipamento com um compilador C instalado, o que não é tão complicado atualmente, considerando que existem compiladores C que rodam em PC´s XT.

No final desta introdução, daremos algumas dicas de como tirar o melhor proveito de um ambiente de programação mais comumente utilizado.

1.1 Um Breve Histórico da Linguagem C

Saber um pouco sobre o passado poderá ajudá-lo a melhor apreciar esta linguagem e por que ela evoluiu até a forma atual.

A linguagem C foi projetada originalmente como um código simbólico para formalizar práticas de programação em uso na época, em meados de 1970. Um pesquisador chamado Dennis M. Ritchie,

que trabalhava nos laboratórios da Bell (Bell Labs - New Jersey/USA), criou-a em 1972 quando ele e Ken Thompson estavam desenvolvendo o sistema UNIX. O UNIX (uma versão monousuária do Multics) teve sua primeira implementação na mesma Bell em 1969, num computador hoje considerado modelo para estudos acadêmicos, o DEC PDP-7 da Digital (atualmente Compaq). Na verdade a linguagem C não surgiu assim tão de repente na cabeça de Ritchie. Ela foi baseada na

linguagem B, criada por Thompson, que se baseou na

Esta é outra estória. O ponto mais

importante é que a linguagem C foi criada como uma ferramenta para programadores. Portanto seu objetivo é ser o mais útil possível.

Muitas linguagens se propõem a ser úteis, mas muitas delas tem outros aspectos. Um dos objetivos principais do PASCAL, por exemplo, é prover os princípios básicos para o aprendizado da programação de computadores. BASIC, por outro lado, lembra muito o inglês, e foi desenvolvida para ser facilmente aprendida por estudantes não familiarizados com os computadores. É claro que estes também são aspectos importantes, mas não são sempre compatíveis com as necessidades diárias dos programadores. Como sendo uma ferramenta para programadores, no entanto, C é considerada uma linguagem bastante amigável, como veremos.

Em 1978, C floresceu e tornou-se a mais popular linguagem de programação de todos os tempos. Naquele ano ocorreu a publicação de “C - A Linguagem de Programação”, escrito por Brian W. Kernigham e Dennis M. Ritchie, que estabeleceu os padrões pelos quais os compiladores C foram julgados por mais de uma década (o padrão nomeado K&R C).

C e UNIX estão intimamente ligados. A tal ponto que em todos os ambientes UNIX ela está

presente. Contudo, não está restrita somente ao mundo UNIX. Este co-desenvolvimento deu ao C uma reputação de “a linguagem de desenvolvimento de sistemas”, pois é útil para escrever desde

sistemas operacionais, compiladores, etc., até utilitários.

A partir de 1980, o UNIX passou a ter uma comercialização mais agressiva pela AT&T. No ano

seguinte, a IBM lançou o PC. Com o lançamento da versão 2.0 do MS-DOS em 1983, que incorporou uma série de conceitos do UNIX, a utilização da linguagem C no mundo PC tornou-se cada vez maior. Basta citar, por exemplo, que alguns dos softwares “best-sellers” anteriores a 1983,

tanto para o MS-DOS quanto para o CP/M, que foram escritos primeiramente em Assembly (dBASE II, dBASE III, WordStar, Lotus 1-2-3 V1.0, etc.) foram reescritos em C (dBASE III Plus, Lotus 1-2-3 V2.0, MS-Word, MS-Chart, etc.).

Atualmente, temos ambientes RAD de desenvolvimento para linguagem C, como por exemplo, o C++ Builder da empresa Borland que está em sua versão 6.0 (igual ao Delphi, porém utilizando C/C++ ao invés de Object Pascal). Com o incremento da utilização do Linux e do FreeBSD a difusão da linguagem está aumentando cada vez mais. A Borland promete para o 2º quarto deste ano a versão equivalente ao C++ Builder que completará o projeto Kylix.

1.2 Por que C?

C, pois:

Tornou-se rapidamente em uma das mais importantes e populares linguagens de programação. Sua utilização cada vez aumenta mais porque as pessoas a conhecem e adotam-na. Após conhecê-la mais intimamente, você também irá reconhecer muitas de suas virtudes. Vamos mencionar algumas delas.

É

uma linguagem moderna que incorpora características de controle que a teoria e a prática da

ciência de computação recomendam. O projeto do C torna natural para os usuários o uso da metodologia “top-down”, da programação estruturada e do projeto modular. Utiliza comandos de estrutura tais como while e for, para loops, ao invés dos comandos goto, que são facilmente mal utilizados e provocam a proliferação de “bugs” (erros). O resultado é um programa mais fácil de entender e manter.

É

uma linguagem eficiente, pois o seu projeto tira a máxima vantagem dos computadores atuais.

O

código gerado tende a ser pequeno e rápido.

É

uma linguagem portável. Isto significa que programas escritos em C em um sistema ou

ambiente operacional podem ser executados, com poucas ou nenhumas modificações, em outros sistemas, bastando, para isso, compilá-los novamente. É a linguagem líder em portabilidade.

Compiladores para C estão disponíveis nos mais diversos tipos de computadores. Desde os de 8 bits até os mais avançados supercomputadores hoje existentes.

É poderosa e flexível (as duas palavras mais favoritas na literatura da ciência da computação). Por exemplo, a maior parte do código do poderoso e flexível sistema UNIX é escrito em C. Ela é uma linguagem de propósitos gerais. Podemos utilizá-la para escrever desde jogos, programas comerciais, utilitários, modelos matemáticos e físicos, processadores de textos, planilhas eletrônicas, compiladores, interpretadores, criação das seqüências de animações em vinhetas, comerciais e filmes, como por exemplo “O Retorno do Jedi”, da série “Guerra nas Estrelas”.

Exibe alguns dos refinados controles usualmente associados com a linguagem Assembly. Se você quiser você pode fazer um ajuste fino no seu programa para obter a máxima eficiência.

É amigável. Ela é suficientemente estruturada para encorajar os hábitos da boa programação sem, no entanto, colocar o programador numa espécie de camisa de força, cheio de restrições.

Em reconhecimento ao crescente uso do C - e, talvez, pelo receio de que se perdesse o controle sobre o padrão de fato que havia surgido - o Instituto Nacional de Padronização Americano (American Standards National Institute - ANSI) criou e encarregou em 1983 o comitê X3J11 de Linguagem de Programação C de adotar um rigoroso padrão a ser seguido pelos implementadores.

Após cinco anos de exaustivos trabalhos e duelos de egos, o comitê conseguiu o que era quase impossível. Eliminou conflitos, particularidades e ambigüidades da linguagem, adicionando alguns atributos especialmente selecionados, resistindo a tentação de saturá-la com incontáveis facilidades, como diversas correspondências propuseram durante a avaliação.

Além do mais, C é uma excelente base; depois de dominá-la, você não terá nenhuma dificuldade para aprender outras linguagens por conta própria.

1.3 Um Pouco de Terminologia

Palavras-chave: são as palavras reservadas por uma determinada linguagem de programação. No C, por exemplo, as palavras while e for não podem ser usadas para propósitos particulares. Veremos que o número de palavras-chave ou reservadas é bastante pequeno.

Sintaxe: refere-se às regras que devemos seguir ao digitar os comandos. Siga religiosamente as indicações da sintaxe, assim você evita problemas.

Semântica: é o significado por detrás das regras de sintaxe.

Algoritmos: são os métodos de resolução para os problemas. É a descrição passo a passo para garantirmos a solução do problema, normalmente escrito em pseudocódigo.

Funções da biblioteca: são funções que estendem as possibilidades naturais de qualquer linguagem. No C, a biblioteca padrão inclui uma série de funções para a entrada e saída, para o manuseio de strings (cadeia de caracteres), para o tratamento de arquivos, para efetuar cálculos matemáticos, para gerenciar a memória, para executar chamadas do sistema e muitas outras.

Pré-processar: é uma etapa pelo qual o compilador C procura e substitui automaticamente determinadas informações a partir de determinadas instruções especais (as para o pré-processador). Isto é feito sem que o programador precise se preocupar. É semelhante ao que fazemos num texto para procurar e substituir determinada seqüência de caracteres.

Código-fonte: é o arquivo ASCII puro contendo os comandos e instruções que desejamos efetuar para resolver determinado problema ou executar uma tarefa específica.

Código-objeto: contém as instruções do programa no seu formato bruto. Nada mais é do que a substituição das nossas instruções colocadas no código-fonte pelos respectivos comandos (ou seqüência destes) que a máquina é capaz de compreender (linguagem de máquina).

Código-executável: é o resultado da link-edição de um ou mais arquivos e das bibliotecas contendo

as funções utilizados pelo programa. Após, é feito alguns acertos de endereços e então se tem o arquivo executável (*.EXE).

Tempo de compilação: é o tempo necessário para efetuar a compilação do programa. Os erros em tempo de compilação são os erros de sintaxe detectados durante a compilação.

Tempo de execução: é o tempo durante o qual o programa está executando. Erros em tempo de execução são erros de lógica, como, por exemplo, efetuar incorretamente um cálculo ou exibir uma informação em local errado.

Depuração: é o processo de localizar e corrigir erros de execução - os bugs. A versão do compilador que usaremos possui um depurador, incluído no ambiente, que facilitará o processo. Pode ser usado para fazer um rastreamento na execução de todo ou parte do programa, inspecionar e alterar o conteúdo de variáveis em tempo de execução e também marcar pontos de parada obrigatória - os breakpoints.

LIB vs. DLL: ambas são bibliotecas. LIB é a extensão usada para bibliotecas estáticas, isto é, são adicionadas ao programa executável sempre que o programa a referenciar – claro, uma vez em cada programa. As DLL’s, como a própria sigla indica, são bibliotecas de viculação dinâmicas, isto é, elas residem em um diretório do sistema operacional (por exemplo, o SYSTEM do Windows 9X). Lá residem à espera de que algum programa as invoque. Ou seja, se eu tenho 10 programas que utilizam a biblioteca xyz.dll, em nenhum deles existirá a própria DLL. Quando uma função desta biblioteca for chamada, o sistema operacional – que sabe onde ela está – a carregará para a memória afim de que seja executado o seu código.

1.4 O Que é um Compilador?

O propósito essencial de um compilador seja qual for a linguagem, é transformar os comandos

simbólicos em um programa acabado (veja a figura 1). O processo de produção de um programa executável em C é dividido em três etapas.

A primeira delas é a criação do(s) arquivo(s) fonte(s). Neste(s) arquivo(s), colocamos definições e

comandos. Para tanto, utilizamos qualquer editor de texto capaz de gravar no formato ASCII puro

(sem comandos de formatação). No caso do C, existem dois tipos de arquivos-fonte: os *.H (cabeçalhos ou “headers”) e os *.C (corpo do programa).

A segunda tarefa é a compilação, o processo de tradução das instruções do(s) programas-fonte(s)

para uma seqüência de comandos que a máquina consegue manipular; aqui são gerados os arquivos objeto (*.OBJ).

Fonte 1 Fonte 2 Fonte n *.C *.C *.C Compilador C Objeto 1 Objeto 2
Fonte 1
Fonte 2
Fonte n
*.C
*.C
*.C
Compilador C
Objeto 1
Objeto 2
Objeto n
Biblioteca
Padrão
Link-editor
Bibliotecas
de
Terceiros
Arquivo Executável

Figura 1 – Os passos para a geração de um programa executável em C.

A última fase é a link-edição. A maioria das linguagens possui bibliotecas (funções prontas para

utilizar). Como o C não possui nenhuma instrução ou palavra-reservada capaz de, por exemplo, fazer entrada e saída de dados, todos os serviços são efetuados por um conjunto de funções que acompanham o compilador - a chamada biblioteca (*.LIB). O comitê ANSI definiu uma série de funções-padrão, que todo compilador C deve possuir. No entanto, cada empresa acrescenta funções próprias. A maioria apresenta os mesmos serviços, porém com funções de nomes diferentes (gotoxy - Borland e moveto – Microsoft, que posicionam o cursor em uma determinada linha e coluna da tela).

Para utilizarmos tais funções, basta “chamá-las”, ou seja, mencioná-las no nosso código-fonte, passando, é claro, todo o argumento necessário para o seu funcionamento. O processo de link- edição é a aglutinação do código objeto gerado a partir de nosso programa (os *.OBJ) com os códigos prontos de todas as funções da biblioteca que estamos utilizando (*.LIB). Após esta etapa, temos o programa executável, que poderá ser executado em qualquer máquina para a qual foi compilado, com total independência. No curso utilizaremos o compilador “Turbo C” versão 2.01 da empresa Borland International; um compilador leve que pode tranqüilamente ser executado em XT´s e também o GNU gcc.

2 O MUNDO “UNIX” LIKE

Existem vários sabores de “UNIX” disponíveis atualmente no mercado. Alguns são pagos, e bem caros, aliás. Outros são gratuitos, ou quase de graça, como é o caso da distribuição brasileira mais conhecida do Linux, a “Conectiva”.

Os sistemas “UNIX” são robustos, confiáveis e muito eficientes no gerenciamento de tudo o que ocorre no computador. Como a maioria dos usuários que chegam a este novo mundo, todos enfrentamos as dificuldades do “novo”, da mudança. Mas, depois de conhecê-lo e verificar as suas virtudes, raríssimas vezes nos decepcionamos.

Os empreendedores da famosa empresa que gosta de ter tudo para si, espalham horrores de infâmias pela net, visando a manter os seus rebentos presos nas suas próprias janelas. Mas basta um dia de peregrinação pela web para verificarmos que a diversidade de programas existentes para o mundo Linux, mais especificamente, aumenta em proporções gigantescas, dia após dia. E o que é mais importante: são em sua grande maioria gratuitos, quando não disponibilizam o código-fonte.

A maioria das distribuições Linux instala o que lá no DOS tínhamos de carregar opcionalmente: o DOSKEY. No Linux, portanto, já é instalado automaticamente. Um outro recurso que auxilia em muito a digitação de comandos é a possibilidade do autocomplemento do comando ou do nome do arquivo que se deseja trabalhar. Isto é obtido através da tecla TAB. Digamos que se queira ver o conteúdo de um arquivo chamado “teste.txt”. Para tanto, usa-se o comando cat e digitaríamos:

cat t<TAB>

cat teste.txt

Se, por um acaso, existirem mais de um arquivo começando com a mesma letra, então soaria um beep. Um segundo toque na tecla <TAB> fará com que o sistema apresente na tela os arquivos cujo nome comece com a letra em questão (ou com as letras até então digitadas).

Bom, para desbravarmos este novo mundo operacional, que também tem janelinhas – porém você tem mais sabores a escolher, preparamos um guia de referência rápido, com os principais comandos.

CUIDADO !!!

Assim como a linguagem C, os sistemas operacionais UNIX-like são sensíveis ao caso,

ou seja, fazem distinção das letras maiúsculas das minúsculas.

2.1 Comando de Auxílio

Todo sistema operacional UNIX tem o seu manual on-line, mais conhecido como man. Ele está disponível para explicar o uso do sistema e seus comandos, inclusive os da linguagem C (C e UNIX

são quase que um só). Para ativar o auxílio, basta digitar man seguida do identificador de comando ou de uma palavra na qual você precisa de maiores informações.

A sintaxe do comando é: man [options] command_name

As opções mais comuns são:

1. -k keyword

2. -M path

3. –a

: lista um resumo do comando para todas as ocorrências encontradas

: path indica o caminho para encontrar as páginas do auxílio

: mostra todas as páginas do manual com ocorrências encontradas

Um exemplo:

man –k password

2.2 Comandos de Navegação e Controle de Diretórios

O sistema de arquivos do UNIX é construído como sendo uma árvore que vai se preenchendo a

partir da raiz, simbolizada pela barra (/). Os diretórios dos usuários e do sistema são organizados

sob a raiz. No UNIX, os usuários não possuem diretórios raiz; eles geralmente se logam no seu diretório próprio (lembrem-se que aqui o sistema é multi-usuário) que está criado abaixo do diretório /home.

A tabela a seguir resume os comandos de navegação e controle de diretórios no Linux (a partir deste

momento, vamos nos deter ao Linux, sem esquecer, porém, que ele també é um sabor do UNIX).

Comando/Sintaxe

Qual o seu propósito

cd [diretório]

Torna o diretório como sendo o corrente

ls [options][diretório ou arquivo]

Mostra o conteúdo do diretório ou as informações do arquivo.

mkdir [options] diretório

Cria o diretório

pwd

Mostra qual é o diretório corrente

rmdir [options] diretório

Remove o diretório

Se você estiver mais familiarizado com o MS-DOS, então esta tabelinha vai lhe ajudar:

Ação

Linux

MS-DOS

Listar o conteúdo do diretório

ls

 

DIR

Criar um diretório

mkdir

MD

/ MKDIR

Alterar o diretório atual

cd

CD / CHDIR

Remover o diretório

rmdir

RD

/ RMDIR

Retornar par o diretório padrão do usuário

cd

 

CD\

Localização na árvore de diretórios

pwd

 

CD

2.3 Comandos de Manutenção de Arquivos

Para criar, copiar remover e alterar permissões de arquivos você utiliza os seguintes comandos:

 

Comando/Sintaxe

Qual o seu propósito

chgrp [options] grupo arquivo

Altera o grupo do arquivo

chmod [options] arquivo/diretório

Altera as permissões de accesso do arquivo ou do diretório

chown [options] proprietário arquivo

Altera o proprietário de um arquivo. Somente o super-usuário

cp [options] origem destino

Copia o arquivo origem para o arquivo destino.

mv

[options] origem destino

Move o arquivo origem para o destino

rm

[options] arquivo/diretórioe

Exclui o arquivo ou o diretório (-r exclui recursivamente o diretório e o seu conteúdo) (-i pergunta antes de remover)

Se você estiver mais familiarizado com o MS-DOS, então esta tabelinha vai lhe ajudar:

Ação

Linux

MS-DOS

Copiar arquivo

cp

COPY

Mover o arquivo

mv

MOVE

Renomear o arquivo

mv

RENAME / REN

Excluir o arquivo

rm

ERASE / DEL

Visualizar todo conteúdo do arquivo

cat

TYPE

Visualizar o conteúdo uma página por vez

more, less, pg

TYPE /P

2.4 Recursos do Sistema

Para reportar e gerenciar os recursos do sistema você utiliza os seguintes comandos:

 

Comando/Sintaxe

Qual o seu propósito

date

Verificar/Alterar a data e hora do sistema

df

Visualisar um resumo da área livre no disco

du

Visualisar um resumo da área em uso no disco

kill

[options] pid# %job

Envia um sinal ao processo identificado por pid# ou job%

ps [options]

Mostra os processos que estão atualmente em execução na máquina

who ou w

Mostra os usuários logados na sua máquina e os processos que estão executando.

bg

Coloca o último processo disparado em execução background

fg

Recoloca o processo em execução foreground

2.5 Impressão de Arquivos

Para imprimir arquivos e gerenciar a fila de impressão do sistema você utiliza os seguintes comandos:

Comando/Sintaxe

Qual o seu propósito

lpq (lpstat) [options]

Verificar o estado das solicitações ainda na fila de impressão

lpr (lp) [options] arquivo

Imprimir o arquivo usando a impressora especificada

lprm (cancel) [options]

Remover uma solicitação da fila de impressão

pr [options] arquivo

Filtra o arquivo e mostra-o no terminal

2.6 Comandos Diversos

Comando/Sintaxe

 

Qual o seu propósito

 

grep / egrep/ fgrep [options] “string” arquivo(s)

Procura

pela

ocorrência

da

“string”

no(s)

arquivo(s) especificados.

 

cmp [options] arquivo1 arquivo2

Compara o arquivo1 com o arquivo2 e lista onde ocorrem as diferenças (arquivos texto ou binários)

diff [options] arquivo1 arquivo2

Compara os dois arquivos e mostra as diferenças (somente arquivos texto)

touch [options] date arquivo

Cria o arquivo se este não existir. Altera a data da última utilização do arquivo para date. Se não for fornecido date usa a data e hora do sistema.

find [options] arquivo

Procura por um arquivo.

 

Todos os comandos aqui apresentados possuem as suas próprias opções. Muitos dele possuem dezenas e dezenas de opções o que torna praticamente impraticável a apresentação destas nesta apostila, uma vez que todas elas poderção ser visualizadas “on the fly” pelo programador/usuário através do comando: man find, por exemplo.

Não se preocupe, com o tempo você vai se acostumando com o ambiente e ficará tudo mais fácil, pois das dezenas de opções apresentadas para um determinado comando, utilizamos mais freqüentemente 3 ou 4, no máximo.

3

GNU gcc

O

compilador de C para o Linux é o comando gcc. Geralmente é interessante saber qual é a versão

do compilador de que você dispõe para quando a solução de algumas complicações for feita utilizando-se dos recursos dos grupos de usuários de Linux disponíveis na internet. Para tanto,

digite:

~> gcc --version

Na maioria dos UNIX o comando de compilação C é o cc. No Linux, no entanto, os comandos cc ou gcc referem-se ao mesmo programa.

3.1 Especificando o Arquivo de Saída

O arquivo de saída padrão do compilador é o arquivo a.out, que é armazenado no diretório atual. Se

você quizer especificar o nome do arquivo de saída (executável), coloque a opção:

–o <nome_arquivo>. Digamos que queiramos compilar o arquivo hello.c e gerar o arquivo executável hello. Então a linha de cmando ficaria assim:

~> gcc hello.c –o hello

3.2 Somente Compilar, Não Gerar Arquivo Executável

Para somente compilar o programa, sem gerar a versão executável do arquivo, você deve utilizar o argumento –c na linha de comando. Digamos que queiramos somente compilar o arquivo hello.c, então devemos montar a linha de comando desta forma:

~>

gcc hello.c –c

3.3 Solicitando uma Compilação com Verificação Completa de Erros

Para compilar um código-fonte solicitando para o compilador ser o mais rigoroso possível com relação aos warnings e errors, devemos incluir a opção –wall na linha de comando. Eis uma linha de comando deste tipo:

~> gcc hello.c –c -wall

3.4 Biblioteca Matemática

Nem todas as aplicações desenvolvidas utilizam-se de funções matemáticas avançadas. Por isso, o compilador C não inclui automaticamente a biblioteca math, mesmo que você forneça o comando de #include <math.h> no seu código fonte. Par, efetivamente, incluir a biblioteca matemática no seu código executável, você deve incluir a opção –lm na linha de comando do compilador.

~> gcc hello.c –lm –wall –o hello

3.5 Gerando Informações de Depuração

O gcc pode incluir informações de depuração no código executável para que um programa de depuração consiga “ligar” as instruções geradas em linguagem de máquina ao código-fonte. Para tanto, devemos incluir a opção –g na linha de comando.

Vamos criar um programa exemplo que vai facilitar o seu entendimento, chamaremos de bug1.c.

1.

/* Exemplo de um programa contendo erro para depuração */

2.

#include <stdio.h>

3.

#include <stdlib.h>

4.

5.

6.

static void funcao1( void )

7.

{

8.

char *ptr_c = 0;

9.

10.

ptr_c = ‘!’; /* Aqui teremos o erro */

11.

}

12.

13.

int main( int argc, char **argv )

14.

{

15.

funcao1( );

16.

return( 0 );

17.

}

Código 2.1 – Exemplo código com erro: bug1.c.

Um dos programas para depuração existentes no Linux é o gdb e ele possui uma versão gráfica também, chamada de kgdb.

Vamos gerar o código executável.

~> gcc –g –o bug1 bug1.c

Agora tente executar o arquivo.

~> ./bug1 <ENTER> (Note a presença do ./ no início da linha)

Deverá, se tudo sair como eu planejei, a seguinte mensagem:

Segmentation fault (core dumped)

Isto significa que o seu programa gerou uma falha e que uma imagem da memória do sistema quando da ocorrência do erro foi salva em um arquivo chamado core (use o cmando ls para certificar-se da existnência dele: ls –l core).

Agora, vamos ao processo de depuração. Primeiro, para verificar a versão do gdb que você possui aplique a mesma fórmula usada no gcc, ou seja, passe o argumento –-version, desta forma:

~> gdb –version

Agora para verificar informações adicionais pos-morten sobre o erro gerado pela aplicação, use o seguinte comando:

~> gdb ./bug1 core

Vai aparecer um texto explicativo sobre o gdb e logo a seguir informações a respeito do arquivo

core e da linha onde ocorreu o problema. Isto não é a sétima maravilha da humanindade, mas ajuda em muito a encontrar problemas. Quando nem o gdb ajudar, aí meu amigo, o jeito é embutir código

tudo bem!”, ou qualquer outra mensagem

de depuração dentro do programa, tipo: “passei por aqui

que nossa vã imaginação ainda puder gerar no momento de pânico, talvez até de ódio. Não adianta, o jeito é relaxar e esfriar a cabeça.

O gdb também possui uma série de comandos internos. Da mesma forma que os demais coamandos,

use o comando man para buscar maiores informações a respeito deles.

3.6 Outras Opções ?! Lembre-se Sempre do man

O compilador C presente no Linux é considerado um comando do sistema, logo, também existem

informações a respeito de como utilizá-lo. Para acessarmos estas informações, basta digitarmos a

linha de comando:

~> man gcc

3.7 Outros Compiladores

Existem muitos outros compiladores de linguagem C disponíveis no mercado; alguns são livres ou gratuitos. O Turbo C, que foi um dos precursores em ambientes integrados de desenvolvimento está disponível no site da Community da Borland (http://community.borland.com), que exige o preenchimento de um cadastro rápido. Depois disso, libera o acesso a todo o site Borland Developer Network (BDN), contendo enorme quantidade de códigos-fonte, artigos e downloads diversos.

O Turbo C (disponível no link http://community.borland.com/article/images/20841/tc201.zip) já faz

e

executar o programa install.exe e seguir os menus.

parte

do

museu

(http://community.borland.com/museum/).

Basta

baixá-lo,

descompacta-lo

A figura 2 apresenta os principais elementos do IDE. O menu de comandos localiza-se na parte

superior da tela. O menu é acessado através da tecla de função F10, ou então, mantendo-se pressionada a tecla ALT e digitando-se a letra inicial dos comandos. Por exemplo, para acessar o menu Options, basta digitar F10 e depois deslocar a barra de seleção, usando as teclas (seta à esquerda) ou (seta à direita) - o menu é circular - até a opção desejada (no caso, Options). Ou, se preferir, usando as chamadas teclas de atalho: ALT + O.

Figura 2 – O ambiente integrado de desenvolvimento do Turbo C. Na parte de downloads

Figura 2 – O ambiente integrado de desenvolvimento do Turbo C.

Na parte de downloads da página da Borland (http://www.borland.com), mais precisamente na seção de downloads http://www.borland.com/products/downloads/download_cbuilder.html) você encontra as versões livres do compilador de linha de comando C++ Builder e do Turbo Debugger.

Também está disponível o tão aguardado ambiente de desenvolvimento C++ da Borland para o Linux. O C++ Builder agora é parte integrante do projeto Kylix (em sua versão 3.0 – você pode escolher a linguagem C/C++ ou a linguagem Delphi – antigo Object Pascal). A versão trial e a livre você pode encontrar no link: http://www.borland.com/products/downloads/download_kylix.html.

Outro ambiente de desemvolvimento para Linux é o K-Develop, que está cada vez mais consistente e interessante. Vale a pena dar uma olhada no site http://www.kdevelop.org/.

4 A ANATOMIA DE UM PROGRAMA EM LINGUAGEM C

Todo programa em C é formado por uma ou mais funções. Podemos dizer que as funções se comparam aos tijolos de construção, ou seja, são os elementos básicos na construção de programas em C.

As funções são formadas por comandos de declaração de variáveis, de atribuições, de controle de fluxo, comandos nulos e também comandos para efetuar chamadas de funções. Veja a figura a seguir.

Programa C Típico #include #define Instruções para o pré-processador main( ) "main" é sempre a
Programa C
Típico
#include
#define
Instruções para o pré-processador
main( )
"main" é sempre a primeira
função executada
comandos
função_1( )
comandos
função_2( )
As funções são o bloco de
construção da linguagem C
comandos
Funções são compostas
por comandos
declarações
atribuição
palavras-chave
São 5 os tipos
funções
de comandos
dados
controle
operadores
nulos
Linguagem C

Figura 3 – A anatomia de um programa em C.

A parte principal de qualquer programa em linguagem C é uma função chamada main. Esta função é a que recebe o controle do sistema operacional quando executamos um programa construído em C. É quem gerencia a execução de todo o programa.

Todo programa deve possuir uma e somente uma função main. No próximo capítulo veremos os comandos de pré-processador.

5 O PRÉ-PROCESSADOR C

C foi desenvolvida para suprir as necessidades dos programadores, e estes gostavam de pré- processadores. Antigamente este programa era separado do compilador; atualmente já fazem parte do compilador propriamente dito. Porém, também está embutido na maioria dos pacotes de desenvolvimento como um programa separado – no Turbo C é o CPP (C Pré-processor).

Este utilitário trabalha sobre o programa antes de enviá-lo ao compilador (por isto são chamados pré-processadores) e, seguindo suas instruções, substituem abreviações simbólicas existentes no programa pelas diretivas que representam. A seguir veremos os comandos mais importantes.

5.1 Definir Constantes Simbólicas: #define

A diretiva de pré-processamento #define, como todas as diretivas, começam com o símbolo #. Pode

aparecer em qualquer parte, valendo desde o seu aparecimento até o final do programa. A maior

utilização para este comando se dá para definição de constantes simbólicas, no entanto a sua utilização pode ser ampliada.

O #define é uma espécie de procura e substitui existente na maioria dos editores de texto. Porém, o

faz automaticamente antes de repassar o código-fonte para o compilador, criando uma espécie de imagem, mantendo o programa-fonte inalterado.

Pode também ser usado para definir macros. Uma macro se parece em muito com uma função. Podemos passar parâmetros para macros assim como para funções. No entanto, as macros são assim chamadas, pois cada vez que aparecem são substituídas pelo seu respectivo código. As macros diminuem o overhead (tráfego no sistema), comparando-as com as funções, entretanto aumentam o tamanho do código executável. Aguarde o exemplo no final do capítulo para compreendermos melhor, por enquanto analise o fragmento de código para o pré-processador C:

#define

DOIS

MSG01

2 /* Podemos usar comentários para explicar /

“Pressione uma tela para continuar

#define

QUATRO

(DOIS + DOIS) /* os comandos em C */

#define

#define

QUADRADO( X )

(X * X) /* isto é uma macro */

1

!VERDADEIRO

/* C nao possui tipos booleanos */

/* ou 0 (zero) */

#define

MAIOR( X, Y )

( X > Y ? X : Y ) /* isto também é uma macro */

#define

VERDADEIRO

#define

FALSO

5.2 Cancelar uma Definição Simbólica: #undef

Como já diz o título, a instrução #undef cancela uma definição criada com um comando #define. Trocando em miúdos: o #define cria uma macrosubstituição e o #undef, a invalida. A partir da linha contendo a instrução #undef, a constante simbólica não terá mais validade.

#undef VERDADEIRO #undef FALSO

5.3 Inclusão de Arquivos: #include

Quando o pré-processador encontra uma diretiva #include ele entende como uma solicitação de mesclar, inserir um outro arquivo no programa. Esta inserção se dá no momento da compilação – o programa fonte não é alterado. Veja os exemplos:

#include

<stdio.h>

#include

“meu_arq.h”

Na primeira linha, o pré-processador procurará pelo arquivo cujo nome é stdio.h no(s) diretório(s) especificado(s) como de inclusão lá no menu Options-Directories. No padrão, ele procurará no diretório INCLUDE do seu compilador favorito. A segunda linha procura o arquivo especificado no diretório corrente. Então, lembre-se de que nomes de arquivos que estejam entre os sinais de “< >” são procurados no diretório INCLUDE e os que aparecerem entre aspas são verificados no diretório atual.

Existem outras diretivas de pré-processamento, porém atualmente não se fazem normalmente necessárias. São elas: #if, #ifdef, #ifndef, #else, #elif e #endif. Falaremos sobre elas durante a explanação teórica nas aulas. Agora, veremos um exemplo mais completo, com várias instruções de pré-processamento.

5.4 Contato Imediato com C

A seguir veremos nosso primeiro programa em C. Para tanto, faça o login no Linux e entre no ambiente gráfico (KDE, Gnome, WindowMaker, etc.) de sua escolha. Aqui no curso vamos padronizar o KDE para facilitar as coisas. No ambiente do KDE, temos um Editor Avançado, que possibilita a digitação de códigos-fonte com o recurso de “syntax hilight” (processo de destacar com cores diferentes os componentes de um código-fonte: identificadores, palavras-chave, etc.).

5.4.1 Primeiro Programa

01.

/* Nosso primeiro programa em C */

02.

#include <stdio.h>

 

03.

#define

INCREMENTO

3

04.

#define

DECREMENTO 2

05.

main( )

06.

{

07.

int num;

08.

09.

num = 1;

10.

printf( “Eu sou um simples “ );

11.

printf( “computador.\n” );

12.

num = num * INCREMENTO;

13.

num = num - DECREMENTO;

14.

printf( “Meu número favorito é %d pois é o primeiro.\n”, num );

15.

}

Código 5.1 – Primeiro exemplo de programa em C.

Vamos fazer um passeio rápido por este exemplo para identificar seus elementos:

A primeira linha do programa é simplesmente um comentário para efeitos de documentação interna,

o que é muito importante em todas as linguagens, porém em C é essencial.

A segunda, a terceira e quarta linhas indicam comandos de pré-processador (todos começam pelo

símbolo de cardinal - #). A segunda linha instrui ao compilador para incluir o arquivo de cabeçalho

STDIO.H. Este arquivo possui todas as definições necessárias para fazer a entrada e saída (I/O) padrão do computador. A terceira e a quarta linhas criam definições, uma espécie de constantes, chamadas de INCREMENTO e DECREMENTO, com valores 3 e 2 respectivamente.

A quinta linha indica o início do programa propriamente dito. Os programas em C são compostos

por funções, como a maioria das linguagens estruturadas. Porém C possui uma peculiaridade: todo programa em C deve possuir uma, e só uma, função com o nome de main. Este nome é especial

para indicar que esta é a função principal, que gerenciará a execução do programa.

A sexta linha apresenta somente o caractere abre chaves ({). Este símbolo é para o C o que o begin

é para outras linguagens, ou seja, o início de um bloco de codificação, no caso, o início do corpo da função principal (main).

A sétima linha mostra a definição de uma variável, chamada num, como sendo inteira. Toda

variável deve ser declarada imediatamente no início do corpo das funções, antes de qualquer utilização.

A oitava linha é deixada em branco para simples questão de documentação. O compilador C ignora

todos os espaços. Use e abuse desta facilidade.

A variável num é inicializada na linha nove. Devemos proceder sempre a inicialização das

variáveis, pois o compilador C nem sempre o faz.

Na linha 10, temos uma chamada de função. A função printf mostra mensagens na tela. No caso, mostrará a seqüência de caracteres entre as aspas.

Continuamos apresentando mensagens também na linha 11. Repare que entre as aspas aparecem dois caracteres estranhos - \n. C é uma linguagem que utiliza metasseqüências de caracteres para efetuar tarefas especiais, todas começando pela contra-barra. Neste caso, solicitando uma quebra de linha ou linefeed.

Agora temos operações matemáticas. A linha doze faz com que a variável num seja incrementada

de 3 unidades. Logo após, na linha treze, recebe o seu valor anterior deduzida de 2 unidades.

Na linha quatorze temos uma nova apresentação de mensagens usando a função printf. Esta função poderia ser traduzida para “imprime mensagens formatadas na tela”. Aqui aparece mais um

conjunto de caracteres estranho - %d. Esta seqüência indica à função printf que ela deve inserir na mensagem o valor da variável que está logo após a própria mensagem.

A última linha é o encerramento da função principal. O símbolo fecha-chaves é utilizado sempre para encerrar um bloco de código ou uma função.

5.4.2 Segundo Programa

01.

/* Nosso segundo programa em C */

 

02.

#include <stdio.h>

 

03.

#define

VERDADEIRO

1

 

04.

#define

MAIS_UM( X )

( X + 1 )

/* incremento de um */

05.

#define

MAIOR( X, Y )

( X > Y ? X : Y )

/* retorna o maior dos dois valores */

06.

#define

Z80

1

/* definição para micro Z-80 */

07.

#define

M6502

2

/* definição para micros Apple II */

08.

#define

I8086

3

/* definição para micros PC XT */

09.

#define

I80386

4

/* definição para micros AT 386 */

10.

#define

COMPUTADOR I8086

/* programa está ajustado para XT */

11.

12.

main( )

 

13.

{

14.

int num1, num2;

 

15.

#ifndef

FALSO

16.

#ifdef VERDADEIRO

 

17.

#define

FALSO

!VERDADEIRO

 

18.

#else

19.

#define

FALSO

0

20.

endif

21.

#endif

22.

23.

#if

COMPUTADOR == Z80

 

24.

num1 = ´Z´; num2 = 80;

25.

#elif COMPUTADOR == M6502

26.

num1 = ´M´; num2 = 6502;

27.

#elif COMPUTADOR == I8086

28.

num1 = ´I´; num2 == 86;

29.

#elif COMPUTADOR == I80386

30.

num1 = ´I´; num2 == 80386

31.

#else

32.

num1 = ´X´; num2 = 9999;

 

33.

#endif

34.

printf( “O meu computador utiliza o chip %c80%d\n\n“, num1, num2 );

35.

if( num2 == 86 || num2 == 386 ) {

 

36.

MAIS_UM( num2 );

 

37.

printf(“Utiliza o coprocessador %c80%d\n\n”,num1, num2 );

38.

}

39.

printf( “Pressione <ENTER> para continuar

);

40.

getchar();

 

41.

}

Código 5.2 – Segundo exemplo de programa em C.

6 TIPOS, OPERADORES E EXPRESSÕES

6.1 Identificadores

Os identificadores são definidos como sendo os nomes utilizados para fazer referência às variáveis,

funções, rótulos e vários outros tipos de objetos definidos pelo usuário. Em C, um identificador pode ter no mínimo um caractere e o tamanho máximo depende da implementação do compilador. Normalmente, o comprimento limite é de 32 posições. Isto não quer dizer que não possamos utilizar identificadores com mais de 32 posições. O tamanho é livre, porém o compilador somente os diferencia até a 32 a posição.

Todos os nomes de identificadores devem seguir algumas regras:

1. Devem sempre iniciar com uma letra ou o sublinhado (underline - não recomendado);

2. Nas demais, são permitidos somente letras, números e o caractere de sublinhado;

3. Ter tamanho máximo de 32 posições (pode ter mais, porém compilador distingue os identificadores somente até a 32 a posição).

Lembre-se também que C é sensível ao caso, ou seja, diferencia as letras maiúsculas das minúsculas. Procure utilizar nomes indicativos, que possuem alguma informação implícita.

6.2 Tipos de Dados

A linguagem C está intimamente ligada ao computador hospedeiro, ou seja, à máquina onde está sendo executado o compilador. Estão disponíveis todos os tipos que o equipamento pode tratar.

Os tipos básicos da linguagem são o caractere - char, o inteiro - int, o ponto flutuante de precisão

simples - float e o de precisão dupla - double. A estes tipos são adicionados alguns modificadores

para alterar o tipo básico, visando melhor adaptá-lo às situações. Os modificadores são: signed, unsigned, short e long.

A seguir veremos os tipos que podem ser manipulados com suas respectivas características,

lembrando que o computador em questão é de 16 bits. O tamanho do tipo int está atrelado ao tamanho da palavra de processamento do processador, sendo assim, os processadores de 32 bis, como os Pentium e Athlon, possuem um inteiro de 32 bits, o short int possui 16 bits e o long int, 64 bits. Tudo isto, claro, se o seu compilador foi escrito para suportar tal arquitetura. Verifique na documentação do seu compilador para obter mais detalhes.

Vejamos, então a tabela dos tipos de dados para o compilador para um processador padrão 8086/80286, como é o caso do Borland Turbo C.

TIPO DE DADO

ESPAÇO OCUPADO

CAPACIDADE

unsigned char

8

bits

0 a 255

char

8

bits

-128 a 127

short int

16

bits

-32.768 a 32.767

unsigned int

16

bits

0 a 65.535

int

16

bits

-32.768 a 32.767

unsigned long int

32

bits

0 a 4.294.967.295

long int

32

bits

-2.147.483.648 a 2.147.483.847

float

32

bits

+/-3.4 X 10 -38 a +/-3.4 X 10 +38

double

64

bits

+/-1.7 X 10 -308 a +/-1.7 X 10 +308

long double

80

bits

+/-3.4 X 10 -4932 a +/-1.1 X 10 +4932

Tabela 8 – Os tipos de dados da linguagem C.

6.3 O Que São Variáveis?

Toda linguagem de programação necessita de algum lugar para armazenar o resultado de seus cálculos ou simplesmente controlar o fluxo do programa. O gerenciamento é feito pela própria linguagem, em tempos de compilação e/ou de execução.

Uma variável nada mais é do que uma posição de memória do computador reservada exclusivamente para guardar informações/dados. Esta posição de memória é referenciada no programa através de um nome – num1 e num2 no nosso exemplo anterior.

O formato básico da declaração de variáveis é:

Tipo_de_Dado

ou

Tipo_de_Dado

Identificador;

Identificador_1, Identificador_2,

, Identificador_N;

As variáveis também podem ser inicializadas durante a sua criação, embora tenhamos algumas restrições. O local onde aparece a declaração da variável afeta a maneira como as outras partes do programa a encaram - veja classes de armazenamento e escopo, logo a seguir.

Exemplos:

char c_opmenu = ´A´; int i_valor = 0; float f_salario = 1234.56; unsigned int ui_sopositivos;

Utilize identificadores sugestivos, que indiquem o conteúdo da variável.

Tome cuidado, pois a linguagem C é sensível ao caso e, portanto, os nomes num1, Num1, NUm1, NUM1, nUM1 e NuM1, por exemplo, são variáveis totalmente distintas.

Atente para o fato da linguagem C não possuir o tipo lógico. Para tanto se utiliza a seguinte convenção:

Valor zero indica falso (todos os bits em 0)

Valor diferente de zero indica verdadeiro (pelo menos um bit ligado)

Identificando alguns tipos de dados:

‘A’

caractere A ou ASCII( 65 ) /* repare os apóstrofos */

32

inteiro

32L

inteiro longo explícito (note a presença do L)

567893

inteiro longo implícito (valor não pode ser armazenado em 2 bytes)

032

inteiro em octal (pois é precedido de 0)

0x32

inteiro em hexadecimal (pois é precedido de 0x ou de 0X – zero xis)

6.4 Criando Variáveis Imutáveis (As Constantes)

Às vezes é interessante criarmos variáveis cujo valor não pode ser mexido em nenhuma parte do programa. É meio contraditório: definir uma variável cujo valor é constante. Mas é exatamente isto. Existe um modificador, o const, de variáveis que as tornam imutáveis, constantes. Quando este modificador é usado, ninguém poderá atualizar, mexer, enfim, ter acesso para escrita na variável.

Um detalhe importante a ser observado é que devemos atribuir-lhes valores na sua declaração, pois, se esquecermos de fazê-lo, jamais poderemos – uma vez que são imutáveis. Isto é, somente aceitam receber um valor na sua declaração, na sua criação.

O formato básico da declaração de variáveis é:

const

Tipo_de_Dado

Identificador = conteúdo;

ou

const

Tipo_de_Dado

Identificador_1 = conteúdo, Identificador_2 = conteúdo, Identificador_N = conteúdo;

Exemplos:

const char letra_A = ´A´; const double PI = 3.141592653; const int deiz = 10;

,

6.5 Classes de Armazenamento e Escopo das Variáveis

A classe de armazenamento precede a declaração do tipo da variável e instrui ao compilador como

este deve armazená-la. Os itens declarados com o especificador auto ou register possuem uma vida local. Os declarados com extern ou static possuem vida global.

O formato básico da declaração de variáveis é:

Classe_de_Armazenamento

Ou

Classe_de_Armazenamento

Exemplos:

Tipo_de_Dado

Tipo_de_Dado

auto char c_opmenu = ´A´; register int i_valor = 0; extern float f_salario = 1234.56; static unsigned int ui_sopositivos;

Identificador;

Identificador _1, Identificador _2, Identificador _N;

,

Os quatros especificadores de classe de armazenamento afetam a visibilidade (ou escopo) de uma variável ou função, assim como sua classe de armazenamento. Visibilidade refere-se ao espaço de programa-fonte no qual uma variável ou uma função pode ser referenciada.

Os itens com vida global sobrevivem durante toda a execução do programa, enquanto que aqueles que possuem vida local, perduram por um determinado período de tempo (enquanto o bloco de código onde foi declarada estiver em execução).

CLASSE DE ARMAZENAMENTO

 

DURAÇÃO DA

VISIBILIDADE

PALAVRA-CHAVE

VARIÁVEL

(ESCOPO)

Automática

auto

Temporária

local

Registrador

register

Temporária

local

Estática

static

Persistente

local

Externa

extern

Persistente

global (a todos os arquivos do projeto)

(Veja observação)

Estática externa

static

Persistente

global (ao arquivo onde é declarada)

Os itens acima da linha de separação são declarações feitas dentro de funções. Os itens abaixo são declarações feitas fora de funções.

Observação: A palavra-chave extern é usada somente para referenciar variáveis que já tenham sido declaradas em algum local; o ato de declarar uma variável fora de qualquer função a torna externa aos elementos do módulo e todas as funções do arquivo podem acessá-la. Se um outro arquivo-fonte quiser acessá-la, necessitará declará-la como externa. Veja a figura logo a seguir.

Tabela 9 – O escopo das variáveis na linguagem C.

As variáveis declaradas dentro de uma função são visíveis somente nesta função. Podemos, portanto, criar várias variáveis com o mesmo nome, porém dentro de funções diferentes. Sempre que uma variável é referenciada (utilizada) e não foi declarada dentro da função, o compilador procura por uma definição global (fora de todas as funções). Se encontrar, tudo bem, senão, indica um erro (variável não declarada). Existe ainda a possibilidade de declararmos dentro de uma função uma variável com o mesmo nome de uma outra global. Quando isto acontecer, o compilador utiliza,

na função, a declaração local. Se, por ventura, quisermos utilizar a variável global, basta utilizar o especificador global (::) antes do nome da variável.

A posição da declaração de uma variável ou função dentro do arquivo-fonte também afeta a classe de armazenamento e a visibilidade. As declarações feitas fora de qualquer função são ditas declarações de nível externo, enquanto que aquelas feitas dentro das funções são chamadas de nível interno.

O significado exato de cada especificador de classe depende do nível onde é colocado e se a

declaração é de uma variável ou de uma função.

Veja um exemplo que ilustra o que foi explicado anteriormente sobre as classes de armazenamento

na figura de número 4, a seguir.

Fonte_1.c

Fonte_1.c

Fonte_1 e Fonte_2 são compilados juntos

Fonte_2.c
Fonte_2.c
Fonte_2.c

Fonte_2.c

   

int twit; static int tum;

main( )

{

 

--------

--------

}

figaro( )

{

 

--------

--------

}

figaro( ) {   -------- -------- } twit é conhecido (visto) por main( ), figaro( ),

twit é conhecido (visto) por main( ), figaro( ), hedge( ) e mostly( ). tum é conhecido (visto) somente por main( ) e figaro( ).

conhecido (visto) por main( ), figaro( ), hedge( ) e mostly( ). tum é conhecido (visto)

Figura 4 – Exemplo de escopo de variáveis.

Existe um quinto modificador de comportamento para variáveis que é o volatile. Este modificador evita que a variável seja alocada em um registrador e que seja alvo de otimizações. Adverte ao compilador que a variável está sujeita a modificações externas durante a sua utilização. Logo, devemos ter muito cuidado e muita certeza ao utilizá-lo.

6.6 Conversão Momentânea de Tipos (Casts)

A linguagem C permite uma adaptação de tipos em tempo de execução, para evitar conflitos em

operações matemáticas, operações com ponteiros, etc. Esta adaptação, uso de cast, nada mais é do que a conversão temporária do tipo de uma variável em outro.

O formato básico dos casts é o seguinte:

(tipo_desejado) identificador

Exemplo:

int x = 9; float k = 0.0;

ou

(tipo_desejado) valor

k

= (float) x; /* Converte o valor inteiro 9 em valor float 9.0 e armazena-o em k */

x

= (int) 3.141; /* Converte o valor 3.141 para inteiro (3) e armazena-o em x */

Para usarmos o cast basta colocarmos o tipo desejado, entre parênteses, na frente da variável ou da expressão que queremos adaptar. Imagine que tenhamos uma operação de multiplicação entre inteiros, que depois terá de ser multiplicado por um número real (float) e cujo resultado tenha de ser transformado em um inteiro longo. Assim, vejamos o fragmento de código mostrado abaixo:

long int k; float real; int meu_num;

real = 3.141592653; meu_num = 5;

/*

CAST

CAST

*/

/*

|

|

*/

k

= ( long int ) ( ( ( float ) (meu_num) * 2.0) * real );

No fragmento acima, a variável meu_num, definida como inteiro, continuará sendo inteira depois de executada a instrução, porém, na realização do cálculo para atribuição do novo valor à variável k, seu valor será convertido de inteiro (2 bytes) para o tipo float (que ocupa 4 bytes). Todo o resultado da expressão, que resulta no tipo float, vai, depois de calculada, sofrer uma transformação para o tipo long int (que é o tipo de k). Tudo isto para evitar conflitos entre tipos.

É bastante útil e deve ser amplamente utilizado quando trabalhamos com variáveis de tipos diferentes, cujos espaços de armazenamentos são variados e dependentes da arquitetura hospedeira do compilador.

6.7 Operadores Aritméticos, Lógicos e Relacionais

A linguagem C apresenta muitos operadores, que atuam exatamente da mesma forma que nas

demais linguagens, e outros, que não fazem parte do acervo comum. Abaixo apresentamos uma

tabela contendo todos os operadores aritméticos da Linguagem C.

SÍMBOLO

OPERAÇÃO

EXPRESSÃO

 

RESULTADO DA AVALIAÇÃO DA EXPRESSÃO

OPERADOR

EXECUTADA

EXEMPLO

 

OPERADORES MATEMÁTICOS

++++

Adição

 

5

+ i

5 somado ao valor da variável i

Subtração

 

x

- y

o

valor da var. x menos o valor da var. y

Multiplicação

22.3

f

22.3 multiplicado pelo valor da variável f

////

Divisão

 

K

/ 3

O

valor da variável k dividido por 3

 

O

valor de um inteiro dividido por outro

inteiro é truncado (22/3 = 7)

%

Mod Resto da divisão

22 % 3

Resto da divisão de inteiros;

 

=

1

só funciona para inteiros.

Menos unário

 

- k

 

Inversão do sinal do valor contido na variável k

 

OPERADOR CONDICIONAL

( ? : )

Condicional

k = (c > 2 ? 1 : 0)

S

c for maior do que dois, então k recebe

o

valor 1, senão, recebe zero

 

OPERADORES BIT A BIT

|

OU bit a bit

 

1 | 2

 

Efetua uma operação

= 3

OU bit a bit

&

E bit a bit

0xFF & 0x0F

Efetua a operação

=

0x0F

AND bit a bit

^

OU exclusivo

0xFF ^ 0x0F

Efetua a operação

=

0xF0

OU-EXCLUSIVO bit a bit

~

Complemento de

~0x03 = 0xFC

Inverte todos os bits 0 para 1

um

e

1 para 0

<<

Deslocamento à

0x0F << 2

Efetua o deslocamento de dois bits à

esquerda

=

0x3C

esquerda (insere zeros à direita)

>>

Deslocamento à

0x1C >> 1

Efetua o deslocamento de 1 bit à direita

Direita

=

0x0E

(incluindo zero(s) à esquerda)

 

OPERADORES DE ATRIBUIÇÃO

OP =

Opera e atribui automaticamente Vale para todos os operadores acima

A += 3

A

= A + 3

X

/= 7 + 2

X

= X / (7 + 2)

=

Atribuição

x

= k * 3;

Coloca o resultado da multiplicação da variável k por 3 na variável x

 

OPERADORES INCREMENTAIS E DECREMENTAIS

++Var

Pré-incremento

 

++A

 

Incrementa a variável A e depois utiliza o valor de A

Var++

Pós-incremento

 

A++

 

Utiliza o valor da variável A e depois incrementa o valor de A

-- Var

Pré-decremento

 

--C

Decrementa a variável C e depois utiliza o valor de C

Var--

Pós-decremento

 

C--

Utiliza o valor da variável C e depois decrementa o valor de C

 

OPERADORES RELACIONAIS

==

Igualdade

i

== 3

Terá valor 1(V) se i for igual a 3 Terá valor 0(F) se i for diferente de 3

!=

Não-igual

j

!= 5

Terá valor 1(V) se j for diferente de 5 Terá valor 0(F) se j for igual a 5

Diferente

 

!

Negação

!2 (Não 2) !0 (Não 0)

Terá valor 0 (!V -> F) Terá valor 1 (!F -> V)

>

Maior

k

> 5

Terá valor 1(V) se k for maior que 5 Terá valor 0(F) se k for menor ou igual a 5

<

Menor

t

< 7

Terá valor 1(V) se t for menor que 7 Terá valor 0(F) se t for maior ou igual a 7

>=

Maior ou igual

k

>= 5

Terá valor 1(V) se k for maior ou igual a 5 Terá valor 0(F) se k for menor que 5

<=

Menor ou igual

t

<= 7

Terá valor 1(V) se t for menor ou igual a 7 Terá valor 0(F) se t for maior que 7

 

OPERADORES LÓGICOS

&&

E

k > 5 && t < 7

Terá valor verdadeiro se e somente se ambas as condições (k for maior do que 5 e t for menor que 7) forem satisfeitas

||

Ou

k>=5 || t <=7

Terá valor verdadeiro se pelo menos uma das condições (k for maior ou igual a 5 ou t for menor ou igual a 7) for satisfeita.

Tabela 10 – Os operadores da Linguagem C.

7 ENTRADA E SAÍDA

A entrada e a saída - E/S - de dados nos programas C é efetuada por funções da biblioteca, uma vez

que a linguagem não possui tais comandos (a diretiva ANSI é manter a linguagem pequena e portável). No entanto, temos um conjunto completo de funções de E/S na biblioteca padrão definida

pelo comitê ANSI. O Turbo C segue o padrão, possuindo todas as implementações exigidas.

A maioria das funções da biblioteca de qualquer compilador C exige que sejam fornecidos alguns

tipos de dados e informações de controle para o seu perfeito funcionamento. Tais informações ficam armazenadas em arquivos separados, chamados de arquivos de cabeçalho (header files) - os

*.H - que devem ser incluídos no programa através das diretivas #include do pré-processador.

O Turbo C apresenta três arquivos de cabeçalho para as funções de entrada e saída:

stdio.h: todas as funções de E/S padrão do C que utilizam bufferização (padrão); conio.h: todas as funções de E/S que acessam diretamente o console (MS-DOS); io.h: todas as funções de E/S de baixo nível que efetuam a transferência direta, sem buffer (UNIX).

7.1 Entrada e Saída de Caracteres

Para a leitura de caracteres, utilizamos as funções abaixo relacionadas:

Bufferizada (aguarda pressionamento de <ENTER>) - devemos incluir stdio.h

c = getchar(); /* Aceita tudo até detectar o <ENTER> */

getchar()

Não bufferizada - devemos incluir conio.h (natural do DOS, deve ser criada no Linux)

getch()

c = getch();

/* Não mostra o caractere digitado na tela */

getche()

c = getche();

/* Mostra o caractere digitado na tela */

Devemos tomar alguns cuidados quando utilizamos a leitura através de getchar(). Uma vez que a entrada é bufferizada, é necessário pressionar o <ENTER> para que seja lido o caractere. No entanto, se for digitado mais de um caractere (o que é freqüente), a função getchar() retira somente o primeiro. Os demais (vale também para o <ENTER>) ficam no buffer, o que às vezes faz com que sejam puladas as próximas leituras de caractere. Para contornar o problema utilize uma função que limpa o buffer de entrada, chamada de fflush, após a realização de getchar(), assim:

c = getchar(); fflush( stdin ); /* stdin é o codinome da entrada padrão (teclado) */

A função getchar também é capaz de realizar a leitura de caracteres diretamente a partir de um

arquivo quando efetuamos o redirecionamento da entrada (programa < entrada.txt). Quando for assim utilizada, para informar o término do arquivo ela retornará o valor EOF, que é o código para final de arquivo. Utilize-o assim mesmo: EOF.

A função getchar(), por ser da biblioteca padrão, não respeita as definições de cores feitas pelo

usuário. Logo, se estiver trabalhando com cores, utilize getch() ou getche().

Para mostrarmos caracteres na tela utilizamos as funções abaixo:

Biblioteca padrão - devemos incluir stdio.h:

putchar()

putchar( ‘A’); ou putchar( 65 );

Biblioteca de console - devemos incluir conio.h:

putch()

putch( ‘b’ ); ou putch( 96 );

Note que podemos fornecer tanto o caractere quanto o seu código ASCII.

Se houver redirecionamento de saída, então a função putchar() deve ser utilizada.

7.2 Entrada e Saída de Cadeias de Caracteres (Strings)

Para a leitura de strings devemos incluir o arquivo de cabeçalho stdio.h, o que possibilita a utilização das funções abaixo relacionadas:

Ler strings:

gets()

gets( var_string ); scanf( “%s”, var_string );

Possibilita leitura de espaços em branco. Encerra leitura ao encontrar o 1 o separador.

scanf()

Como você observou nas observações acima, existem diferenças no funcionamento das funções. Ambas são bufferizadas, o que significa que só encerrarão a leitura quando for detectado o pressionamento da tecla <ENTER>. gets automaticamente substitui o <ENTER> pelo terminador (´\0´) e aceita espaços em branco e tabulações. Já a scanf, que é uma função curinga, capaz de ler vários tipos de dados (note o %s - string) retorna somente o que foi digitado até o primeiro separador (um espaço em branco ou tabulação), substituindo-o pelo terminador, o restante permanece no buffer.

Em ambas as funções, lembrem-se de declarar sempre a string com uma posição a mais do que o necessário, espaço necessário para o terminador. Não existe um controle do tamanho, logo se você declarar uma string com 10 posições, poderá ler no máximo 9. Não é possível controlar a quantidade de caracteres lidas com estas funções, logo podemos ter problemas, principalmente se for lida uma quantidade que extrapola o tamanho definido. Se isto acontecer, serão preenchidos os bytes consecutivos à variável, não importando se estão alocados para outras variáveis ou não.

Para escrever strings devemos utilizar as seguintes funções:

puts()

puts( var_string ); ou puts (“Ola mundo !”);

printf()

printf(“%s”, var_string) ou printf(“Oi mundo!”);

As funções acima colocam na tela (ou em um arquivo - quando redirecionamento da saída) uma cadeia de caracteres. Se for o conteúdo de uma variável, ambas mostrarão todos os caracteres até que seja encontrado o terminador de string.

7.3 Entrada e Saída Formatada de Dados

As funções scanf e printf são funções da biblioteca padrão responsável pela entrada e saída formatada de dados, respectivamente. Formatada, pois respeitam uma definição de tipo e também porque fazem transformações automáticas de dados.

7.3.1 A Função de Entrada Formatada scanf

O formato da função scanf é sempre o seguinte:

scanf( formato, argumento ); ou scanf( lista_identificadora_dos_formatos, lista_de_argumentos );

O formato, sempre como uma “string”, segue o seguinte esqueleto:

% [*] [comprimento] [F|N] [h|l|L] caractere_identificador_do_tipo

Cada especificação de formato começa pelo caractere de percentual. Após, seguem em ordem:

Caractere opcional supressor de atribuição: [*];

Definição opcional de tamanho: [tamanho];

Modificador opcional do tipo de ponteiro do argumento [F|N];

N

= transforma o argumento em ponteiro para perto;

F

= transforma o argumento em ponteiro para longe;

Modificador opcional do tipo de argumento: [h|l|L];

h

= inteiro curto

l

= inteiro longo (se o identificador de tipo especifica um inteiro)

l

= real em dupla precisão (se o especificador de tipo for real)

L = real longo em dupla precisão (válido somente para especificadores de tipo real);

Caractere identificador do tipo a ser lido (ver tabela abaixo):

IDENTIFICADOR

ENTRADA ESPERADA

TIPO DO ARGUMENTO

 

TIPOS PARA NÚMEROS

d

Inteiro decimal

Ponteiro para inteiro Ponteiro para inteiro longo

D

Inteiro decimal

o

Inteiro octal

Ponteiro para inteiro Ponteiro para inteiro longo

O

Inteiro octal

i

Inteiro decimal, octal ou hexadecimal

Ponteiro para inteiro Ponteiro para inteiro longo

I

Inteiro decimal, octal ou hexadecimal

u

Inteiro decimal sem sinal

Ponteiro para inteiro sem sinal Ponteiro para inteiro longo sem sinal

U

Inteiro decimal sem sinal

x

Inteiro hexadecimal

Ponteiro para inteiro Ponteiro para inteiro longo

X

Inteiro hexadecimal

e

Real - ponto flutuante

Ponteiro para real Ponteiro para real

E

Real - ponto flutuante

F

Real - ponto flutuante

Ponteiro para real

g

Real - ponto flutuante

Ponteiro para real Ponteiro para real

G

Real - ponto flutuante

 

TIPOS PARA CARACTERES

S

Cadeia de caracteres (string)

Ponteiro para um vetor de caracteres

C

Caractere

Ponteiro para caractere

%

Caractere de percentual

Ponteiro para caractere para armazenar o %

 

TIPOS PARA PONTEIROS

N

 

Ponteiro para inteiro. Armazena o número de caracteres lidos com sucesso até o aparecimento deste %n.

P

Ponteiro na forma hexadecimal:

%p converte o ponteiro para o tipo de ponteiro utilizado pelo modelo de memória especificado

YYYY: ZZZZ ou ZZZZ

Tabela 15 – Identificadores de tipo na leitura de dados.

Campos de entrada podem ser qualquer um dos tipos abaixo:

Todos os caracteres até o próximo caracter de espaço(sem incluí-lo);

Todos os caracteres até o primeiro que não puder ser convertido para o tipo especificado (como um 8 ou 9 quando solicitado inteiro em octal);

Até n caracteres, onde n é o tamanho especificado.

Existe a possibilidade de restringirmos a entrada de dados através do fornecimento de um conjunto de pesquisa, colocado entre colchetes. No entanto só valem para leitura de dados que serão armazenados em strings. Vejamos os exemplos:

%[abcd] = procura por um dos caracteres a, b, c ou d no campo de entrada. %[^abcd] = procura por caracteres exceto a, b, c e d no campo de entrada.

Podemos também utilizar a facilidade da definição de um intervalo de leitura. Se quiséssemos restringir a leitura aos dígitos decimais poderíamos fazer de duas formas:

%[0123456789] = forma normal; %[0-9] = utilizando a facilidade do intervalo.

Outros exemplos:

%[A-Z]

para ler só as letras maiúsculas;

%[0-9A-Za-z]

para ler todos os dígitos decimais e todas as letras;

%[A-FT-Z]

para ler todas as letras maiúsculas de A até F e de T até Z.

Veja alguns exemplos onde o hífen não define o intervalo, mas sim o próprio hífen:

%[-+*/]

para ler os 4 operadores matemáticos;

%[z-a]

para ler os caracteres z, - e a;

%[+0-9-A-Z]

para ler + e -, intervalo de 0 a 9 e de A até Z;

%[+0-9A-Z-]

idem ao anterior;

%[^-0-9+A-Z]

para ler todos os caracteres exceto + e -, e os intervalos de 0 à 9 e de A até Z.

A função scanf irá encerrar a leitura de um campo, e começar a processar o próximo (se existir),

quando:

O caractere supressor de atribuição (*) aparecer na especificação de formato; o campo de entrada corrente é lido, mas não armazenado;

Já foi lido a quantidade especificada de caracteres;

O próximo caractere não pode ser convertido segundo o tipo especificado (por exemplo, uma letra quando o tipo for um número);

O próximo caractere não aparece no conjunto (normal ou invertido) de pesquisa.

Retorna:

A quantidade de variáveis de lidas, convertidas e armazenadas com sucesso;

O EOF ao detectar o final de arquivo (quando do redirecionamento da entrada);

0 (zero) se nenhuma variável foi lida.

Exemplos:

int var_i; float var_f; char var_str[50]; - - - scanf( “%d %f”, & var_i, &var_f ); scanf( “%[^-0-9]s”, var_str );

Veja também as variações desta função (cscanf, sscanf e fscanf) na biblioteca.

7.3.2 A Função de Saída Formatada printf

O formato da função printf é sempre o seguinte:

printf( formato, argumento ); ou printf( lista_identificadora_dos_formatos, lista_de_argumentos );

O formato, sempre como uma “string” segue o seguinte esqueleto:

% [flags] [comprimento] [.prec] [F|N|h|l|L] caractere_identificador_do_tipo

Cada especificação de formato começa pelo caractere de percentual. Após, seguem em ordem:

Seqüência opcional de caracteres de sinalização: [flags]:

:

Alinha o resultado à esquerda, preenchendo o espaço restante à direita com

Mostra o sinal do valor;

Mostra um espaço em branco para os números positivos e o sinal de - para

-

espaços em branco. Se não aparecer, o resultado vai ser alinhado à direita,

preenchendo o vazio à esquerda com zeros ou brancos;

+ :

branco:

os negativos;

# :

Especifica que o argumento deve ser convertido usando uma forma alter- nativa (veja a tabela abaixo das formas alternativas);

Note que o sinal de mais (+) tem prioridade sobre o espaço em branco, se ambos aparecerem.

CARACTER DE CONVERSÃO

 

COMO O # (CARDINAL) AFETA O ARGUMENTO

c, s, d, i, u

 

Não sofre alteração.

 

Um algarismo 0 (zero) precederá o argumento

 

0

(quando este for diferente de zero).

x

ou X

0x (ou 0X) precederá o argumento.

 

O

resultado sempre conterá um ponto decimal

e, E, f

mesmo que o valor não possua casas decimais. Normalmente, o ponto decimal só aparece nestes resultados se um dígito o sucede.

 

O

mesmo que e e E, porém os zeros

g

ou G

desnecessários, predecessores ou sucessores, irão

 

aparecer.

Tabela 16 – Formas alternativas de conversão.

Definição opcional de tamanho: [tamanho]; Pelo menos n posições serão mostradas. Se o valor possuir menos do que n posições, o restante é preenchido com brancos, respeitando a flag de alinhamento. 0n: Pelo menos n posições são mostradas. Se o valor possuir menos do que n caracteres, o espaço à esquerda serão preenchidos com zeros. : A lista de argmento fornece a especificação de tamanho, que deve preceder o argumento que está sendo formatado atualmente.

n:

Especificador opcional de precisão: [.prec];

não especificado:

usa o padrão:

1

para os tipos d,i,o,x e X;

6

para os tipos e, E e f;

todos os dígitos significativos para os tipos g e G; todos os caracteres até o NULL para o tipo s; o tipo c não é afetado pela precisão usa o padrão para os tipos d, i, o, u, x e X;

.0:

para os tipos e, E e f o ponto decimal não é mostrado; .n: n caracteres ou n casas decimais serão mostradas. Se o valor de saída possuir mais do que n caracteres, a saída será truncada ou arredondada (dependendo do tipo de dado);

:

A lista de argumento fornece o especificador de precisão, que deve ser fornecido antes do argumento, precedê-lo;

Note que o fornecimento de uma precisão explícita de 0 (zero) casas decimais para os tipos inteiros (d, i, o, u, x e X) e o valor a ser mostrado vale 0 (zero), nenhum dígito será mostrado (será branco), como se não fosse apresentado.

CARACTER DE

COMO A PRECISÃO (.PREC) AFETA A CONVERSÃO

CONVERSÃO

d, i,

.n especifica que pelo menos n dígitos serão mostrados. Se o valor a ser impresso possuir menos do que estes n dígitos, o valor será preenchido à esquerda com zeros (0).

o, u,

x, X

e, E,

.n especifica que n caracteres serão mostrados depois do ponto

f

decimal, sendo que o último dígito representa um arredondamento das demais casas (0-4 -> +0; 5-9 -> +1).

g, G

.n especifica que, quando muito, n dígitos significativos serão mostrados.

c

.n não afeta a saída em nada

s

.n especifica que serão mostrados no máximo n caracteres.

Tabela 17 – Modificando a precisão dos números.

Modificador opcional do tipo de argumento: [F|N|h|l|L];

F

=

argumento é lido como sendo um ponteiro longo;

N =

argumento é lido como um ponteiro curto - NÃO deve ser usado no modelo de memória HUGE;

h

=

argumento é interpretado como sendo um inteiro curto para os tipos d, i, o, u,

l =

x ou X; argumento é interpretado como sendo:

L =

um inteiro longo (para os tipos d, i, o, u, x ou X); um real com dupla precisão- double - (para os tipos e, E, f, g ou G);

argumento é interpretado como sendo um real com dupla precisão longo – long double - (para os tipos e, E, f, g ou G);

Caractere identificador de tipo a ser mostrado (veja a tabela a seguir):

Identificador

Argumento de Entrada

Formato da Saída

 

Tipos Para Números

d

Inteiro

Inteiro decimal com sinal

i

Inteiro

Inteiro decimal com sinal

o

Inteiro

Inteiro octal sem sinal

u

Inteiro

Inteiro decimal sem sinal

x

Inteiro

Inteiro hexadecimal sem sinal com as letras minúsculas (a, b, c, d, e, f)

X

Inteiro

Inteiro hexadecimal sem sinal com as letras maiúsculas (A, B, C, D, E, F)

f

Real - ponto flutuante

Valor real com sinal na forma [-]dddd.dddd

e

Real - ponto flutuante

Valor real com sinal na forma:

[-]d.dddd e [+/-]ddd (exponencial)

E

Real - ponto flutuante

Valor real com sinal na forma:

[-]d.dddd E [+/-]ddd (exponencial)

g

Real - ponto flutuante

Valor real tanto na forma e ou f, baseado no tipo do valor e na precisão:

usa formato exponencial se valor for maior do que a precisão especificada ou se o valor for menor do que -

4.

G

Real - ponto flutuante

Valor real tanto na forma e ou f, baseado no tipo do valor e na precisão, mas usa E para o expoente:

usa formato exponencial se valor for maior do que a precisão especificada ou se o valor é menor do que -4.

 

Tipos Para Caracteres

s

Ponteiro para a string

Mostra todos os caracteres até que o terminador NULL (´\0´) seja encontrado ou tenha alcançado a precisão desejada

c

Caractere

Um só caractere

%

 

Mostra o próprio caractere %

 

Tipos Para Ponteiros

n

Ponteiro para inteiro

Armazena o número de caracteres escritos com sucesso até o aparecimento deste %n.

p

Ponteiro

Imprime o argumento como um ponteiro:

ponteiros far: XXXX: XXXX ponteiros near: YYYY (somente o offset)

Tabela 18 – Identificadores de tipo para a saída de dados.

No formato, podemos utilizar as seqüências de escape para efetuar algumas operações especiais, como avançar para a linha seguinte. Lembre-se de que uma seqüência de escape é considerada como sendo UM caractere simples, logo deve estar entre apóstrofos.

A tabela a seguir apresenta estes caracteres especiais.

CONSTANTE

VALOR ASCII

SIGNIFICADO

\a

0x07

Alarme (beep)

\b

0x08

Retrocesso ou backspace

\t

0x09

Tabulação horizontal

\n

0x0A

Nova linha

\v

0x0B

Tabulação vertical

\f

0x0C

Avanço de formu