You are on page 1of 191

PDF gerado usando o pacote de ferramentas em cdigo aberto mwlib. Veja http://code.pediapress.com/ para mais informaes.

PDF generated at: Mon, 26 May 2014 05:07:58 UTC


Programar em C
Contedo
Pginas
Capa 1
Por que aprender a linguagem C 1
Histria da linguagem C 2
Pr-requisitos 5
Utilizando um compilador 6
Noes de compilao 8
Um programa em C 9
Conceitos bsicos 10
Variveis 13
Tipos de dados 15
Constantes 20
Entrada e sada simples 22
Operaes matemticas (Bsico) 32
Operaes matemticas (Avanado) 34
Operadores 38
Controle de fluxo 44
Funes 54
Pr-processador 64
Exerccios 69
Vetores 80
Strings 83
Passagem de parmetros 87
Tipos de dados definidos pelo usurio 88
Enumerao 94
Unio 97
Estruturas 99
Ponteiros 105
Mais sobre variveis 120
Mais sobre funes 127
Bibliotecas 131
Entrada e sada em arquivos 134
Gerenciamento de memria 144
Sockets 150
Makefiles 152
Lista de palavras reservadas 160
Seqncias de escape 160
Lista de funes 161
Lista de bibliotecas 162
Dicas de programao em C 163
Listas encadeadas 167
Pilha 170
Fila ou Queue 172
rvores binrias 174
Algoritmos de ordenao 179
Algoritmo de alocao 182
Lista de autores 184
Referncias
Fontes e Editores da Pgina 185
Fontes, Licenas e Editores da Imagem 187
Licenas das pginas
Licena 188
Capa
1
Capa
ndice>> Ir para o ndice >>
Por que aprender a linguagem C
Em uma era onde o software est cada vez mais presente no nosso dia a dia importante ter algumas bases de
programao, para isso importante ter um bom material com explicaes claras e exemplos, e o livro Programar em
C se presta bem ao exerccio.
Mas por que C e no Java ou Basic, ou ainda Perl? Linguagens como o Java ou Perl so linguagens a base de
bytecode interpretado por uma mquina virtual sendo assim no um cdigo interpretado diretamente pelo
processador. Ao contrrio de muitas linguagens de programao, o C permite ao programador enderear a memria
de maneira muito parecida como seria feito em Assembly. Linguagens como o Java ou o Perl fornecem mecanismos
que permitem que o programador faa o seu trabalho sem ter que se preocupar com a atribuio de memria ou com
apontadores. Geralmente isso bom, uma vez que bastante trabalhoso lidar com a alocao de memria quando
escrevemos aplicaes com algoritmos de alto nvel. No entanto, quando lidamos com tarefas de baixo-nvel como
aquelas que um ncleo (kernel) tem obrigao de desempenhar, como a de copiar um conjunto de bytes para uma
placa de rede, torna-se altamente necessrio um acesso direto memria algo que no possvel fazer com Java.
C pode ser diretamente compilado em cdigo de mquina, e por isso rpido e eficiente. Alm disso, C permite
personalizar como implementar cada coisa bsico, como alocao de memria, permitindo adaptaes para melhorar
desempenho.
Vale lembrar que os softwares interpretadores de script ou bytecode, como Java e Python, so escritos em linguagens
como C e C++.
Ser uma surpresa que C seja uma linguagem to popular?
Como num efeito domin, a prxima gerao de programas segue a tendncia dos seus ancestrais. Sistemas
operacionais desenvolvidos em C sempre tm bibliotecas de sistema desenvolvidas em C. Essas bibliotecas so
usadas para criar bibliotecas de programa (como Xlib, OpenGL ou GTK), e seus desenvolvedores geralmente
decidem usar a mesma linguagem das bibliotecas de sistema. Desenvolvedores de aplicao usam bibliotecas de
programa para desenvolver processadores de texto, jogos, tocadores de mdia, etc. Muitos vo decidir trabalhar com
a mesma linguagem que a biblioteca foi escrita, e assim o processo continua...
C uma das linguagens de programao mais populares para se escrever sistemas operacionais, como o Microsoft
Windows, o Mac OS X e o GNU/Linux. Sistemas operacionais comunicam-se diretamente com o hardware; no h
nenhuma camada mais baixa para mediar seus pedidos. Originalmente, os sistemas operacionais eram escritos na
linguagem Assembly, o que resultava em um cdigo muito rpido e eficiente. Entretanto, escrever um sistema
operacional em Assembly um processo tedioso (lento), e produz um cdigo que funcionar somente em uma
Por que aprender a linguagem C
2
arquitetura de CPU, tal como o x86 ou ARM. Escrever um sistema operacional em uma linguagem de alto nvel, tal
como C, possibilita que os programadores readaptem o sistema operacional a vrias arquiteturas sem precisar
reescrever todo o cdigo. O ncleo (kernel) Linux um exemplo de sistema operacional escrito em C, com apenas
algumas sees do cdigo escritas em Assembly, para poder executar instrues que s existem em uma ou outra
arquitetura e para algumas otimizaes.
Histria da linguagem C
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Histria
Desenvolvimentos iniciais
Kenneth Thompson ( esquerda) e Dennis Ritchie ( direita), os criadores da
linguagem C
O desenvolvimento inicial da linguagem C
ocorreu nos laboratrios Bell da AT&T
entre 1969 e 1973. Segundo Ritchie, o
perodo mais criativo ocorreu em 1972.
Deu-se o nome "C" linguagem porque
muitas das suas caractersticas derivaram de
uma linguagem de programao anterior
chamada "B". H vrios relatos que se
referem origem do nome "B": Ken
Thompson d crdito linguagem de
programao BCPL, mas ele tambm criou
uma outra linguagem de programao
chamada 'Bon, em honra da sua mulher
Bonnie.
Por volta de 1973, a linguagem C tinha se
tornado suficientemente poderosa para que grande parte do ncleo de UNIX, originalmente escrito na linguagem de
programao PDP-11/20 Assembly, fosse reescrito em C, tornando-se um dos primeiros ncleos de sistema
operacional implementado em uma linguagem sem ser o Assembly. Como exemplos anteriores pode-se citar o
sistema Multics (escrito em PL/I) e TRIPOS (escrito em BCPL).
Histria da linguagem C
3
C de K&R
Em 1978, Ritchie e Kernighan publicaram a primeira edio do livro The C Programming Language. Esse livro,
conhecido pelos programadores de C como "K&R", serviu durante muitos anos como uma especificao informal da
linguagem. A verso da linguagem C que ele descreve usualmente referida como "C de K&R". (A segunda edio
do livro cobre o posterior padro ANSI C, descrito abaixo.) K&R introduziram as seguintes caractersticas na
linguagem:
Tipos de dados struct
Tipos de dados long int
Tipos de dados unsigned int
O operador =+ foi alterado para +=, e assim sucessivamente (a anlise lxica do compilador confundia o operador
=+. Por exemplo, i =+ 10 e i = +10).
C de K&R frequentemente considerado a parte mais bsica da linguagem cujo suporte deve ser assegurado por um
compilador C. Durante muitos anos, mesmo aps a introduo do padro C ANSI, ele era considerado o "menor
denominador comum" em que programadores de C se apoiavam quando uma portabilidade mxima era desejada, j
que nem todos os compiladores eram atualizados para suportar na ntegra o padro C ANSI, e o cdigo C de K&R
razoavelmente bem escrito tambm vlido em relao ao C ANSI.
Nos anos que se seguiram publicao do C K&R, algumas caractersticas "no-oficiais" foram adicionadas
linguagem, suportadas por compiladores da AT&T e de outros vendedores. Estas incluam:
Funes void e tipos de dados void *
Funes que retornam tipos struct ou union
Campos de nome struct num espao de nome separado para cada tipo struct
Atribuio a tipos de dados struct
Qualificadores const para criar um objeto s de leitura
Uma biblioteca-padro que incorpora grande parte da funcionalidade implementada por vrios vendedores
Enumeraes
O tipo de ponto-flutuante de preciso simples
Os Padres C ANSI e C ISO
Durante os finais da dcada de 1970, a linguagem C comeou a substituir a linguagem BASIC como a linguagem de
programao de microcomputadores mais usada. Durante a dcada de 1980, foi adotada para uso no PC IBM, e a sua
popularidade comeou a aumentar significativamente. Ao mesmo tempo, Bjarne Stroustrup, juntamente com outros
nos laboratrios Bell, comeou a trabalhar num projeto onde se adicionavam construes de linguagens de
programao orientada por objetos linguagem C. A linguagem que eles produziram, chamada C++, nos dias de
hoje a linguagem de programao de aplicaes mais comum no sistema operativo Windows da companhia
Microsoft; C permanece mais popular no mundo UNIX.
Em 1983, o Instituto Norte-Americano de Padres (ANSI) formou um comit, X3j11, para estabelecer uma
especificao do padro da linguagem C. Aps um processo longo e rduo, o padro foi completo em 1989 e
ratificado como ANSI X3.159-1989 "Programming Language C". Esta verso da linguagem frequentemente
referida como C ANSI. Em 1990, o padro C ANSI, aps sofrer umas modificaes menores, foi adotado pela
Organizao Internacional de Padres (ISO) como ISO/IEC 9899:1990. Um dos objetivos do processo de
padronizao C ANSI foi o de produzir um sobreconjunto do C K&R, incorporando muitas das caractersticas
no-oficiais subsequentemente introduzidas. Entretanto, muitos programas tinham sido escritos e que no
compilavam em certas plataformas, ou com um certo compilador, devido ao uso de bibliotecas de funes
no-padro e ao fato de alguns compiladores no aderirem ao C ANSI.
Histria da linguagem C
4
C99
Aps o processo ANSI de padronizao, as especificaes da linguagem C permaneceram relativamente estticas por
algum tempo, enquanto que a linguagem C++ continuou a evoluir. (Em 1995, a Normative Ammendment 1 criou
uma verso nova da linguagem C mas esta verso raramente tida em conta.) Contudo, o padro foi submetido a
uma reviso nos finais da dcada de 1990, levando publicao da norma ISO 9899:1999 em 1999. Este padro
geralmente referido como "C99". O padro foi adotado como um padro ANSI em Maro de 2000.
As novas caractersticas do C99 incluem:
Funes em linha
Levantamento de restries sobre a localizao da declarao de variveis (como em C++)
Adio de vrios tipos de dados novos, incluindo o long long int (para minimizar a dor da transio de
32-bits para 64-bits), um tipo de dados boolean explicito e um tipo complex que representa nmeros
complexos
Disposies de dados de comprimento varivel
Suporte oficial para comentrios de uma linha iniciados por //, emprestados da linguagem C++
Vrias funes de biblioteca novas, tais como snprintf()
Vrios arquivos-cabealho novos, tais como stdint.h
O interesse em suportar as caractersticas novas de C99 parece depender muito das entidades. Apesar do GCC e
vrios outros compiladores suportarem grande parte das novas caractersticas do C99, os compiladores mantidos pela
Microsoft e pela Borland no, e estas duas companhias no parecem estar muito interessadas adicionar tais
funcionalidades, ignorando por completo as normas internacionais.
Resumo em ingls
Em 1947, trs cientistas do Laboratrio Telefonia Bell, William Shockley, Walter Brattain, e John Bardeen criaram o
transistor.A computao moderna teve incio. Em 1956 no MIT o primeiro computador completamente baseado em
transistores foi concludo, the TX-0. Em 1958 na Texas Instruments, Jack Kilby construiu o primeiro circuito
integrado. Mas mesmo antes do primeiro circuito integrado existir, a primeira linguagem de alto nvel j tinha sido
escrita.
Em 1954 Fortran, a Formula Translator, foi escrito. Comeou como Fortran I em 1956. Fortran veio a ser Algol 58, o
Algorithmic Language, em 1958. Algol 58 veio a ser Algol 60 em 1960. Algol 60 veio a ser CPL, o Combined
Programming Language, em 1963. CPL veio a ser BCPL, Basic CPL, em 1967. BCPL veio a ser B em 1969. B veio
a ser C em 1971.
B foi a primeira lngua da linhagem C diretamente, tendo sido criado no Bell Labs por Ken Thompson. B era uma
linguagem interpretada, utilizada no incio, em verses internas do sistema operacional UNIX. Thompson e Dennis
Ritchie, tambm da Bell Labs, melhorou B, chamando-NB; novas prorrogaes para NB criaram C, uma linguagem
compilada. A maioria dos UNIX foi reescrito em NB e C, o que levou a um sistema operacional mais porttil.
B foi, naturalmente, o nome de BCPL e C foi o seu sucessor lgico.
A portabilidade do UNIX foi a razo principal para a popularidade inicial de ambos, UNIX e C; rather than creating
a new operating system for each new machine, system programmers could simply write the few system dependent
parts required for the machine, and write a C compiler for the new system; and since most of the system utilities
were written in C, it simply made sense to also write new utilities in the language.
Pr-requisitos
5
Pr-requisitos
pr-requisito para um bom aprendizado de qualquer linguagem de programao conceitos sobre lgica de
programao.
Alm disso, para programar em C, voc precisa de um editor de textos e um compilador, discutidos a seguir.
Editor
Para editar o cdigo de um programa, apenas necessrio um editor de textos, qualquer um, at mesmo o Bloco de
Notas do Windows.
No entanto, h diversos editores que apresentam recursos que facilitam a edio de programas, como:
destaque/colorao de sintaxe, complementao de cdigo, formatao (indentao) automtica, ajuda integrada,
comandos integrados para compilar etc. Entre todos eles podemos destacar o Vim e o Emacs, ambos com verses
para Windows, Linux e Mac OS.
Em sistemas GNU/Linux, a maioria dos editores de texto j possuem recursos para facilitar a edio de programas
em C. Principalmente, devido ao fato da maioria deles (dos programas) e boa parte do sistema terem sido
programados utilizando C ou C++.
Entretanto, o editor apenas edita o cdigo. Para transforma-lo em linguagem de mquina e o executar, precisaremos
de um compilador.
Compilador
O cdigo em linguagem C consiste em instrues que o computador dever seguir. O compilador realiza o trabalho
de traduzir essas instrues para linguagem de mquina, de forma a poderem ser executadas pelo computador.
Ligador ou linker
A ligao de arquivos consiste na construo de uma imagem memria que contm partes de cdigo compilados
separadamente. Em outras palavras ele une os arquivos objetos e as bibliotecas (estticas, dinmicas) para formar
uma nova biblioteca ou um executvel.
Obtendo um compilador
Existem diversos compiladores disponveis:
Para Windows ou DOS
MinGW (antigo mingw32): uma espcie de gcc para Windows. o compilador includo com o Dev-C++, da
Bloodshed. O Dev-C++ um IDE (sigla em ingls para Ambiente Integrado de Desenvolvimento) que facilita a
edio e compilao de programas. Tem traduo para Portugus do Brasil.
Borland C++: a Borland disponibilizou um compilador gratuito que funciona em linha de comando, como
alternativa ao IDE comercial.
DJGPP: porte do gcc para DOS. Tambm funciona no Windows, mas se o objetivo for rodar no Windows,
recomenda-se o uso do mingw, que pode usufruir de todos os recursos do Windows.
Microsoft Visual C++: compilador comercial da Microsoft, que tambm tem um IDE. O Framework .NET,
gratuito, tambm inclui o compilador (em linha de comando) do Visual C++.
Bloodshed DEV-C++: ambiente de desenvolvimento integrado livre que utiliza os compiladores do projeto GNU
para compilar programas para o sistema operacional Microsoft Windows.
Pr-requisitos
6
Para Linux/Unix-like
gcc: um conjunto de compiladores oficiais do projeto GNU, de cdigo aberto. Costumam vir instalados na
maioria das distribuies GNU/Linux e est disponvel para diversas plataformas, principalmente para as
baseadas em sistemas do tipo unix.
GNU linker: o ligador do projeto GNU o nome do programa "ld" e faz parte do pacote GNU Binary Utilities.
Links externos
CodeBlocks
[1]
: pgina para download do CodeBlocks, uma IDE para C ao estilo do Dev-C++, porm, mais nova.
Dev-C++
[2]
: pgina para download do Dev-C++.
DJGPP
[3]
: pgina oficial, com informaes e links para download.
GCC
[4]
: pgina oficial do compilador para diversas plataformas.
Referncias
[1] http:/ / www. codeblocks. org
[2] http:/ / www. bloodshed.net/ dev/ devcpp.html
[3] http:/ / www. delorie.com/ djgpp/
[4] http:/ / gcc.gnu.org/
Utilizando um compilador
Compiladores: viso geral
Um compilador , geralmente, um programa de modo texto, que deve ser operado diretamente da linha de comando,
sem nenhuma interface grfica. Essa uma das razes pelas quais muitas pessoas preferem usar IDEs. No entanto,
saber um pouco sobre como usar o compilador pela linha de comando pode vir a ser til, por exemplo quando voc
no tiver um IDE disposio. No nenhum bicho-de-sete-cabeas, e a sintaxe da maioria dos compiladores
semelhante.
Para executar o compilador, voc precisa abrir um terminal (ou "prompt de comando", como costuma ser chamado
no Windows, ou ainda console). lgico que se voc estiver em um sistema sem ambiente grfico (como o DOS),
voc no precisa fazer isso.
O Windows s tem um terminal nativo, que o interpretador de comandos dele (cmd.exe ou command.com).
Pacotes como o Cygwin e o MSys (do mesmo projeto que o MinGW) incluem terminais alternativos que funcionam
basicamente maneira do Linux.
No Linux, alm dos terminais de modo texto, h vrios emuladores de terminal, entre os quais esto o XTerm, o
Konsole (KDE) e o Terminal do Gnome. O uso de todos eles idntico.
gcc
Com o gcc, compilador da GNU utilizado principalmente no sistema operacional linux ou de tipo unix, voc pode
executar a compilao e a montagem separadamente ou com um nico comando. Se voc tem vrios arquivos-fonte,
mais recomendvel executar as duas etapas separadamente: se voc atualizar apenas um arquivo, s precisar
recompilar o que atualizou e depois remontar. No entanto, se voc est desenvolvendo um projeto grande,
recomendvel usar ferramentas de automao do processo de compilao, como o make.
Resumo:
gcc [OPES] nome_do_arquivo
Utilizando um compilador
7
Aqui so listadas algumas das opes do gcc:
-c: Compila o cdigo fonte mas no faz as ligaes. A sada um arquivo objeto.
-o: serve para dar um nome ao arquivo de sada.
-O2: ativa otimizao no nvel 2
-g: salva os smbolos de depurao (o que permite usar um depurador)
-Wall: ativa todos os avisos do compilador
-pedantic: ativa os avisos necessrios para que o cdigo esteja estritamente de acordo com os padres
Para compilar o arquivo "programa.c", gerando o cdigo-objeto "programa.o":
gcc [OPES] -c programa.c
Para gerar o executvel "programa binario" bin ou "programa.exe" no Windows/DOS a partir do cdigo-objeto:
gcc [OPES] -o programa[.bin] programa.o
Para gerar o executvel diretamente a partir do arquivo-fonte:
gcc [OPES] -o programa[.bin] programa.c
Visual C++
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
Em alguma verso no especificada do Visual C++, para compilar o arquivo "programa.c", gerando o cdigo-objeto
"programa.obj":
cl /c programa.c
Para gerar o executvel "programa.exe" a partir do cdigo-objeto:
link /out:programa.exe programa.obj
Para gerar o executvel a partir do arquivo-fonte:
cl programa.c
Noes de compilao
8
Noes de compilao
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.
Compilao
Todo o cdigo em linguagem C que escrevermos deve ser salvo em um arquivo, em formato texto, com a extenso
".c". Esse cdigo no tem significado nenhum para a unidade de processamento; para que o processador possa
executar nosso programa, este deve ser traduzido para a linguagem de mquina. Essa traduo se chama compilao
e feita pelo programa denominado compilador.
O compilador l todo o cdigo e cria um arquivo executvel, em linguagem de mquina, especfica para uma
arquitetura de processadores e para um tipo de sistema operacional, o que significa que um programa compilado no
Windows, por exemplo, no rodar nativamente no Linux se simplesmente copiarmos o executvel. Devemos, para
isso, recompilar o cdigo-fonte do programa.
No Windows, os arquivos executveis so aqueles com extenso ".exe". No Linux, os executveis so simplesmente
arquivos com o atributo "executvel".
Etapas da compilao
O processo que chamamos corriqueiramente de compilao na verdade um conjunto de etapas:
o preprocessamento, etapa em que o pr-processador (programa s vezes acoplado ao compilador) l o
cdigo-fonte e faz algumas substituies para que o programa possa ser compilado. Em C, o preprocessador tem
diversos usos: compilao condicional (por exemplo, usar trechos diferentes do cdigo para sistemas operacionais
diferentes), macros, substituio de smbolos e incluso de arquivos externos que declaram funes e variveis.
a verificao sinttica, que procura por eventuais erros nos cdigos dos programas: parnteses no fechados,
falta de ponto-e-vrgula no final da instruo, etc. Todos esses problemas so alertados e causam a interrupo da
compilao.
a compilao propriamente dita, que transforma o cdigo preprocessado em um programa-objeto, que est em
linguagem de mquina porm no pronto para ser executado.
a linkedio (linking, em ingls) dos programas-objeto e bibliotecas necessrias em um nico executvel, feita
pelo linkeditor (linker). Em C, pode-se distribuir um programa em vrios arquivos-fonte, o que ajuda na
organizao e permite compilar apenas a parte do programa correspondente quando necessrio realizar alguma
mudana. Na montagem, todas as partes constituintes do programa so deslocadas e/ou cortadas conforme
necessrio para que tenhamos um programa executvel.
Um programa em C
9
Um programa em C
Um programa em C
comum que o primeiro programa escrito em uma linguagem de programao seja um programa que escreve "Hello
world!" ("Ol mundo!"). Apresentamos o cdigo e, a seguir, analisaremos cada uma de suas linhas. No se preocupe
se no entender ainda alguns aspectos, tudo ser abordado detalhadamente mais adiante.
Note que o nmero das linhas dado apenas para facilitar a referncia; se for copiar o cdigo, lembre-se de tirar os
nmeros de linha.
1. /* o meu primeiro programa */
2. #include <stdio.h>
3. int main()
4. {
5. printf ("Ol, mundo!");
6. return (0);
7. }
O texto do programa tambm conhecido como cdigo do programa ou simplesmente cdigo fonte. O cdigo fonte
o programa escrito na linguagem de programao. Em nosso caso acima, chamamos cdigo C ou simplesmente
cdigo.
Voc deve copiar o cdigo acima em um editor de texto como notepad e salv-lo como ola.c (sem acento).
Lembre-se de remover os nmeros das linhas. Caso contrrio o cdigo no ir compilar. Esse arquivo agora
representa o cdigo fonte do programa escrito em C.
Salvando o cdigo acima em um arquivo com a extenso ".c" e seguindo as instrues de compilao do do captulo
de utilizao de compilador, voc dever ver como resultado um "Ol, mundo!" na tela. A seguir vamos a anlise do
cdigo.
A primeira linha um comentrio, que para o compilador no tem nenhum significado. Qualquer texto que esteja
entre as marcaes /* e */, podendo inclusive ocupar vrias linhas, ser considerado como comentrio e ser
completamente ignorado pelo compilador. muito til como documentao, explicando o que as prximas linhas de
cdigo fazem.
A linha 2 pede que seja inserido o contedo do arquivo stdio.h (que est num lugar j conhecido pelo compilador).
Esse arquivo contm referncias a diversas funes de entrada e sada de dados (stdio abreviao de Standard
Input/Output, ou Entrada e Sada Padronizadas), de modo que voc precisar dele em praticamente todos os
programas ele o meio de quase toda comunicao com o teclado, com a tela e com arquivos.
[1]
Os programas em C so organizados em funes todo cdigo em C deve fazer parte de uma funo. Em
particular, todo programa deve ter uma funo chamada main, pela qual ser iniciada a execuo do programa. A
funo definida, no nosso exemplo, na linha 3, e delimitada pelas chaves { }.
A palavra-chave int significa que a funo devolve um valor inteiro (voc pode pensar nesse valor exatamente como
o valor de uma funo em matemtica).
Na linha 5, executamos a funo printf, que imprime na tela os parmetros que lhe foram passados no nosso
exemplo, passamos a seqncia de caracteres "Ol, mundo!" como parmetro. Essa uma das funes definidas em
um cabealho da biblioteca C, o arquivo stdio.h.
Note o ponto-e-vrgula no final da linha: todas as instrues em C devem terminar com um ponto-e-vrgula. (Essa
uma causa muito comum de erros de compilao).
Um programa em C
10
Na linha 6, dizemos que a funo main deve devolver (ou retornar) o valor 0 e terminar sua execuo. (Esse o valor
inteiro que dissemos que amos retornar na linha 3.)
O padro da linguagem C diz que a funo main deve devolver um valor inteiro, e esse valor diz se o programa foi
executado com sucesso ou no. O valor zero indica que o programa foi finalizado sem nenhum erro, e valores
diferentes de zero podem indicar diferentes erros. Voc no precisar se preocupar com isso no incio do seu estudo
em C o valor devolvido por um programa geralmente usado em scripts, quando (por exemplo) um comando s
pode ser executado se o anterior tiver ocorrido com sucesso.
Compilando o programa
Linux
A maioria das distribuies linux j possuem compilador C na instalao padro. Para compilar o programa
acima(ola.c) abra um terminal, entre na pasta onde o arquivo se localiza e digite o seguinte comando:
gcc -o ola ola.c
O compilador ir gerar o arquivo executvel chamado ola que pode ser executado da seguinte forma:
./ola
[1] Esse comando uma diretiva do pr-processador; voc aprender mais sobre esses comandos na seo Pr-processador.
Conceitos bsicos
Voc j viu um programa bsico em C. Antes de comear a se dedicar ao estudo de C, bom que voc compreenda
alguns termos e alguns aspectos da linguagem, o que facilitar sua compreenso dos captulos seguintes. A seguir,
formalizaremos alguns aspectos da estrutura bsica da linguagem.
Estrutura bsica
Um programa em C basicamente estruturado em blocos de cdigo. Blocos nada mais so que conjuntos de
instrues, e devem ser delimitados com chaves ({ ... }). Um bloco tambm pode conter outros blocos.
Uma instruo geralmente corresponde a uma ao executada, e deve sempre terminar com ponto-e-vrgula (;).
O compilador ignora espaos, tabulaes e quebras de linha no meio do cdigo; esses caracteres so chamados
genericamente de espao em branco (whitespace). Ou seja, os trs trechos a seguir so equivalentes:
printf("Ol mundo");return 0;
printf ("Ol mundo");
return 0;
printf(

"Ol mundo"

);
return
0
;
Conceitos bsicos
11
No entanto, voc achar muito mais fcil de ler um estilo de cdigo mais parecido com o segundo exemplo.
Costuma-se usar (mas no abusar de) espaos e tabulaes para organizar o cdigo.
A linguagem sensvel utilizao de maisculas e minsculas. Por exemplo, se voc escrevesse Printf no
lugar de printf, ocorreria um erro, pois o nome da funo totalmente em minsculas.
Escopo
Geralmente, em programao, no queremos que outras funes usem as variveis que estamos manipulando no
momento. O conceito de escopo est justamente relacionado a isso. Escopo o nvel em que um dado pode ser
acessado; em C h dois nveis: local e global. Uma varivel global pode ser acessada por qualquer parte do
programa; variveis locais podem ser acessadas apenas dentro do bloco onde foram declaradas (ou nos seus
sub-blocos), mas no fora dele (ou nos blocos que o contm). Isso possibilita que voc declare vrias variveis com o
mesmo nome mas em blocos diferentes. Veja um exemplo:
int a;
{
int a;
int b;
}
{
int b;
}
As duas variveis chamadas b so diferentes e s podem ser acessadas dentro do prprio bloco. A primeira varivel
a global, mas s pode ser acessada no segundo bloco, pois a varivel local a no primeiro bloco oculta a varivel
global de mesmo nome. Note que isso possvel em C, e tome cuidado para no cometer erros por causa disso.
Introduo s funes
Funes so muito usadas, no s em C, mas em linguagens de programao em geral. Uma funo basicamente
um bloco de cdigo que realiza uma certa tarefa. Quando queremos realizar aquela tarefa, simplesmente fazemos
uma chamada de funo para a funo correspondente.
Uma funo pode precisar que o programador d certos dados para realizar a tarefa; esses dados so chamados
argumentos. A funo tambm pode retornar um valor, que pode indicar se a tarefa foi realizada com sucesso, por
exemplo; esse valor o valor de retorno. Podemos fazer uma analogia com as funes matemticas: as variveis
independentes so os argumentos e o valor numrico da funo o valor de retorno.
Em C, para chamar uma funo, devemos escrever o seu nome, seguido da lista de argumentos (separados por
vrgula) entre parnteses, mesmo que no haja nenhum argumento. Lembre que a chamada de funo tambm uma
instruo, portanto devemos escrever o ponto-e-vrgula no final. Alguns exemplos de chamadas de funes:
funcao(arg1, arg2, arg3);
funcao();
Se quisermos saber o valor de retorno de uma funo, podemos armazen-lo numa varivel. Variveis sero
introduzidas logo adiante, mas a sintaxe muito fcil de aprender:
valor_de_retorno = funcao(arg1, arg2);
Vejamos um exemplo completo:
Conceitos bsicos
12
//quadrado.c
//calcula o quadrado de um nmero
#include<stdio.h>
int square( int num1 )
{
return num1 * num1;
}
int main(){
int number;
int result;
printf("\nDigite um numero: ");
scanf("%d", &number);
result = square(number);
printf("O Quadrado de %d eh: %d", number, result);
return 0;
}
Em C, todo o cdigo (exceto as declaraes de variveis e funes) deve estar dentro de funes. Todo programa
deve ter pelo menos uma funo, a funo main, que por onde comea a execuo do programa.
Expresses
Um conceito muito importante em programao o de expresso. Expresses so conjuntos de valores, variveis,
operadores e chamadas de funes que so avaliados ou interpretados para resultar num certo valor, que chamado
o valor da expresso. Por exemplo:
3 * 4 + 9 uma expresso de valor 21;
a + 3 * b uma expresso equivalente expresso matemtica a + 3b;
foo() uma expresso cujo valor o valor de retorno da funo foo.
Comentrios
Muitas vezes bastante til colocar comentrios no cdigo, por exemplo para esclarecer o que uma funo faz, ou
qual a utilidade de um argumento, etc. A maioria das linguagens de programao permite comentrios; em C, eles
podem aparecer de duas maneiras:
/* Comentrios que podem
ocupar vrias
linhas.
*/
e
Conceitos bsicos
13
// Comentrios de uma linha s, que englobam
// tudo desde as duas barras at o final da linha.
Tudo que estiver entre as marcas /* e */ ou entre // ser ignorado pelo compilador. Note que os comentrios de
uma linha s (iniciados por //) foram incorporados ao padro da linguagem apenas em 1999, e portanto alguns
compiladores podem no os suportar. As verses mais recentes do GCC no tero problema em suportar esse tipo de
comentrio.
Variveis
Variveis
Em um programa, existe a necessidade de se guardar valores na memria, e isso feito atravs de variveis, que
podem ser definidas simplificadamente como nomes que se referem a lugares na memria onde so guardados
valores. Ao declararmos uma varivel, no apenas estamos reservando um espao de memria, como tambm
estamos associando um nome a ele, o identificador. Ao invs de utilizarmos o endereo da varivel na memria, que
seria geralmente notado na forma hexadecimal, como por exemplo 0x0012FED4, referimo-nos ao endereo apenas
pelo seu nome. Apenas para deixar claro, a prpria notao em hexadecimal j uma simplificao, pois
computadores na verdade trabalham com binrio.
Em C, para utilizar uma varivel, ela deve ser primeiramente declarada, ou seja, devemos requisitar o espao
necessrio para essa varivel. Aps reservar um espao na memria, o computador ir associar a ele o nome da
varivel. Se voc no declarar uma varivel e tentar utiliz-la, o compilador ir avis-lo disso e no continuar a
compilao.
Declarando variveis
Genericamente, para declarar uma varivel, usamos a seguinte instruo:
tipo_da_varivel nome_da_varivel;
Por exemplo, para declarar uma varivel do tipo int com o nome a, podemos escrever
int a;
sempre necessrio indicar o tipo da varivel, pois cada tipo tem um tamanho diferente, ou seja, ocupa mais ou
menos espao na memria do computador. Mais adiante introduziremos os tipos de varivel.
Atribuindo valores
Se quisermos associar um valor a uma varivel, usamos o operador = (igual):
a = 5;
Nesse caso, estamos pedindo que o computador guarde o valor 5 no espao alocado varivel a.
Observao: Apesar de este operador se assemelhar ao igual da matemtica, sua funo diferente. Para verificar a
igualdade de dois valores, usamos o operador de comparao "==" (dois iguais).
possvel tambm atribuir um valor a uma varivel ao mesmo tempo que ela declarada, o que chamado de
inicializar a varivel. Por exemplo:
int a = 5;
Variveis
14
possvel tambm declarar mais de uma varivel de um mesmo tipo em uma nica instruo, separando os nomes
por vrgulas. Tambm possvel inicializar as variveis dessa maneira:
int a, b, c, d;
int e = 5, f = 6;
int g, h = 2, i = 7, j;
Como o prprio nome j diz, o valor existente numa varivel pode ser mudado, da mesma maneira que ele
normalmente atribudo. Se tivermos:
int a;
a = 2;
a = 3;
no final o valor da varivel a ser 3.
Exemplo de erro
a = 25;
Mesmo sabendo que um exemplo de erro, escreva o cdigo acima em um arquivo .c e tente compilar para se
familiarizar com as mensagens de erro do compilador, assim voc saber o que fazer quando elas ocorrerem.
No exemplo acima no foi declarada a varivel a, ao tentar compilar o compilador informa que o smbolo a no foi
definido.
Nomes de variveis
Existem algumas restries quanto ao nome que podemos dar a variveis. Essas regras se aplicam tambm para
nomear funes e estruturas.
Os nomes de variveis devem ser nicos no mesmo escopo: no podemos ter duas variveis com o mesmo nome.
O nome pode ser igual ao de outra varivel j existente em escopo superior, porm recomendado fortemente que
no se use variveis iguais sob pena de tornar o cdigo do programa incompreensvel ou de difcil anlise;
O C, assim como muitas outras linguagens de programao, sensvel utilizao de maisculas e
minsculas(case sensitive). Portanto, o cdigo a seguir seria vlido e geraria trs variveis diferentes:
int nome;
int NOME;
int Nome;
Em nomes de variveis, podemos usar letras maisculas ou minsculas (de A a Z, sem acentos), algarismos
arbicos (0-9) e o caractere sublinhado (_), mas o primeiro caractere deve ser uma letra ou o sublinhado.
Algumas palavras no podem ser usadas para nomes de variveis por serem palavras reservadas (palavras que tm
significado especial na linguagem).
O padro C atual especifica que nomes de at 31 caracteres devem ser aceitos. Alguns compiladores podem at
aceitar nomes maiores que isso, mas no considere isso uma regra e no use nomes to longos.
Tipos de dados
15
Tipos de dados
'
At agora voc s viu as variveis do tipo int, que servem para guardar nmeros inteiros. A linguagem C tem
outros tipos fundamentais. So eles:
int, para nmeros inteiros entre -2147483647 e 2147483647, utiliza 4 bytes;
char, para caracteres individuais do padro ASCII, utiliza 1 byte;
float, para reais entre (aproximadamente) 10
-38
e 10
38
, utiliza 4 bytes, preciso de 7 dgitos;
double, para reais entre (aproximadamente) 10
-4932
e 10
4932
, utiliza 8 bytes, preciso de 15 dgitos;
bool, para indicar true (verdadeiro) ou false (falso), utiliza 1 byte; Presente apenas no padro C99 em diante.
Explicando bits e bytes
Podemos pensar na memria do computador como uma fita, uma grande fita feita de frames sequenciais.
Em cada um desses frames, podemos colocar uma certa voltagem: tem voltagem ou no tem voltagem: se tem
voltagem associamos o valor 1, se no tem voltagem associamos o valor 0. Da termos a linguagem binria de zeros
e uns.
Agora podemos fazer combinaes se tivermos posio de zeros e uns, da direita para a esquerda.
00000000 1 Combinao
00000001 2 Combinao
00000010 3 Combinao
00000011 4 Combinao
00000100 5 Combinao
00000101 6 Combinao
00000110 7 Combinao
00000111 8 Combinao

E na verdade podemos estender este conceito para um nmero infinito de combinaes.
Ora o que aconteceu que nos bastavam pouco menos de 256 combinaes (8 bits ordenados) para termos uma
combinao para cada letra, maiscula e minscula, nmero, pontos de exclamao, interrogao, etc. e isso era o
suficiente para a nossa comunicao. Mas para haver um certo consenso para que uma dada combinao desse um
dado smbolo surgiu a tabela ASCII (surgiram outras tabelas quando se quis colocar os smbolos de outras lnguas,
como o japons ou o chins ver tabela ISO) Portanto com 8 bits ou 8 casas conseguamos ter qualquer smbolo que
utilizamos. A esse conjunto de 8 bits chamamos de byte, mais convenientemente. Portanto, um byte tem 8 casas de
zeros /uns , ou seja 2 elevado a 8 d as 256 combinaes. E o byte a unidade bsica que o C++ consegue operar e
representado pelo tipo char.
Pergunta: Quando tivermos mais do que 256 bytes acrescenta-se um outro byte?
Sim. Com dois bytes o nmero de combinaes 256*256.
Pergunta: Qual a razo do computador usar apenas bytes como medida mnima? Ser que no seria possvel utilizar
7 bits ou 5 bits?
No possvel pelo fato do computador s entender 0 e 1 ento no caso impossvel se ter um nmero mpar de
bits porque tudo tem que ter o 0 e o 1 por isso que tudo na informtica evolui multiplicando-se por 2 (32, 64, 256,
512)
Tipos de dados
16
Nmeros inteiros
Se dissermos que 2 bytes representam inteiros, poderemos utilizar as 65 536 combinaes, pois 2 bytes -16bits-
temos 2 elevado a 16 = 65 536 e isso dar-nos-ia esses nmeros todos. Assim se quisermos apenas os positivos com o
zero temos de [0, 65535].
Se quisermos ter nmeros negativos e positivos podemos dividir esse valor a meio e d 32768 para cada lado
positivo e negativo, mas como temos de ter o zero vamos roubar um valor ao lado positivo e ento ficamos com o
intervalo [-32768, 32767]. E ficamos com as mesmas 65 536 combinaes.
Apresentamos inteiro com 2 bytes, mas eles podem ter 4 bytes, isso vai depender do processador do computador, ie,
com quantos bytes consegue ele lidar ao mesmo tempo.
Tambm existem outros tipos, como short (ou short int), que serve para inteiros menores, long (ou long int) para
inteiros maiores. Qualquer tipo inteiro pode ser precedido por unsigned (o signed para COM negativos), para cortar
os nmeros negativos, permitindo maior capacidade de armazenamento de nmeros positivos. Alguns compiladores
aceitam o long long, para aumentar ainda mais o tamanho da varivel, alguns desses s aceitam para o tipo int,
outros tambm para o tipo double.
Podemos alterar a maneira como os dados so guardados com os modificadores de tipo. Voc pode modificar os
tipos de duas maneiras.
Tamanho: short e long
Voc pode modificar o tamanho de uma varivel usando os modificadores de tipo, que so dois: short e long.
Note que float e char no podem ser modificados em tamanho.
short diminui o espao necessrio para guardar a varivel (diminuindo tambm a gama de valores que esta pode
assumir). S pode ser usado com int.
long aumenta o espao tomado pela varivel, e portanto aumenta seu valor mximo e/ou sua preciso. Pode ser
usado com int e double.
O padro C de 1999 adicionou um terceiro modificador, suportado pelos compiladores mais recentes, inclusive o
gcc: long long, que aumentaria ainda mais a capacidade da varivel. Alguns deles suportam esse modificador
apenas para o tipo int, e outros suportam tambm para double.
Uma observao necessria: segundo o padro, no existe nenhuma garantia de que uma varivel short int
menor que uma varivel int, nem que long int maior que int. Apenas garantido que int no maior
que long nem menor que short. De fato, nos sistemas x86 de 32 bits (ou seja, a maioria dos computadores
pessoais atualmente), o tamanho de int igual ao de long. Geralmente, int ser o tamanho nativo do
processador ou seja, 32 bits num processador de 32 bits, 16 bits num processador de 16 bits etc.
Sinal: signed e unsigned
Existe outro tipo de modificador, que define se o nmero vai ser guardado com sinal ou no. So os modificadores
signed e unsigned, suportados pelos tipos inteiros apenas.
signed diz que o nmero deve ser guardado com sinal, ou seja, sero permitidos valores positivos e negativos.
Esse o padro, portanto esse modificador no muito usado.
unsigned diz que o nmero deve ser guardado sem sinal. Com isso, o valor mximo da varivel aumenta, j
que no teremos mais valores negativos. Por exemplo, com uma varivel char podemos guardar valores de -128
a 127, mas com uma varivel unsigned char pode guardar valores de 0 a 255.
Para usar esses modificadores, devemos coloc-los antes do nome do tipo da varivel, sendo que o modificador de
sinal deve vir antes do modificador de tamanho caso ambos sejam usados. Por exemplo:
unsigned char c;
short int valor;
Tipos de dados
17
unsigned long int resultado;
Nota: Voc pode abreviar short int e long int para simplesmente short e long, respectivamente.
Tabela de tipos inteiros
Convm ver a tabela de tipos inteiros.
Tipo Num de bits Formato para leitura com scanf Intervalo
Inicio Fim
char 8 %c -128 127
unsigned char 8 %c 0 255
signed char 8 %c -128 127
int 16 %i -32.768 32.767
unsigned int 16 %u 0 65.535
signed int 16 %i -32.768 32.767
short int 16 %hi -32.768 32.767
unsigned short int 16 %hu 0 65.535
signed short int 16 %hi -32.768 32.767
long int 32 %li -2.147.483.648 2.147.483.647
signed long int 32 %li -2.147.483.648 2.147.483.647
unsigned long int 32 %lu 0 4.294.967.295
Nota: O tipo long 32 bits como int em computadores de arquitetura 32 bits e 64 bits em computadores de
arquitetura 64 bits no padro LP64 (Mac OS X e Unix).
Nmeros de ponto flutuante
Os nmeros de ponto flutuante so uma tentativa para guardar nmeros reais, como 3,1415 (pi), -2,3333, 0,00015,
6,02 10
23
. Ao contrrio dos nmeros reais, os nmeros representveis pelo hardware so finitos. A maneira como
os tipos de ponto flutuante so armazenados abstrata para o programador, entretanto, o hardware segue o padro
IEEE 754 (Standard for Floating-Point Arithmetic).
O armazenamento feito usando notao cientfica binria.
Decimal Notation Scientific Notation E Notation
123.45 1.2345 x 102 1.2345E2
0.0051 5.1 x 10-3 5.1E-3
1,200,000,000 1.2 x 109 1.2E9
Os tipos float e double servem para guardar nmeros de ponto flutuante. A diferena entre os dois , alm do
intervalo de dados, a preciso. Geralmente, o tipo float guarda dados (com sinal positivo ou negativo) de 3,4E-38
a 3,4E+38 (alm do zero). J double suporta nmeros to pequenos quanto 1,7E-308 e no mximo 1,7E+308.
float 32 %f 3,4E-38 3.4E+38
double 64 %lf 1,7E-308 1,7E+308
long double 80/128 %Lf 3,4E-4932 3,4E+4932
Nota: O tipo long double trabalha em mquinas x64 no padro LP64 (Mac OS X e Unix)
Tipos de dados
18
Bool
Este tipo surgiu porque muitas vezes apenas se quer ter 2 valores: sim/no ; verdadeiro/falso. Tem o tamanho de um
byte e tem apenas dois valores 0 e 1 que corresponde a true e false.
Por que guardar um bool num byte quando se pode utilizar apenas um bit? A razo que o computador usa no
mnimo o byte, no o bit.
Endereos
Os vrios locais na memria so identificados por um address, que tem uma lgica sequencial numerada. So
necessrios 16 bits para guardar o endereo de um byte. dito de outra forma so necessrios 2 bytes para guardar a
morada de um byte. ser isto verdade?!! isso quer dizer que se guardarmos os endereos de todos os bytes, s temos
1/3 da memria disponvel para guardar valores. Bem isto um pouco estranho, mas repare-se que apenas vamos
guardar os addresses das variveis reservadas. Depois as variveis nem sempre so de 1 byte, por isso apenas iremos
guardar o endereo do primeiro byte e no de todos. por fim faz sentido guardar o endereo de outro endereo? Os
endereos de memria (addresses) so normalmente expressos em linguagem hexadecimal (base 16, utilizam os 10
algarismos mais as 6 primeiras letras de a a f - do alfabeto para fazerem as 16).
Compatibilidade de dados na atribuio de valor
Se tentarmos colocar um valor diferente do tipo esperado da varivel? Temos um problema de compatibilidade de
dados:
Caso 1: Declaramos um int e colocamos uma letra
Aqui no teremos problemas. Os literais de caracteres so, nativamente, do tipo int. O resultado ser um
inteiro que contm o valor ASCII do caractere dado.
Caso 2: Declaramos um int e colocamos uma string (sequncia de caracteres)
Aqui teremos um erro de compilao, em que nos diz que no conseguimos converter "const char [5]"
em "int". Perceba com isso que o compilador tem alguns sistemas de converso note o caso 3.
Caso 3: Declaramos um int e colocamos um float
Neste caso, se colocarmos 77.33, ir ser apenas guardado o valor 77, perdendo-se a parte decimal.
Caso 4: overflow declaramos um short e colocamos um valor maior que o mximo
Lembre-se que o tipo short guarda valores de 32767 a 32767. Se colocarmos 32768 (e o compilador no
estender esses limites), no vai acontecer nenhum erro de compilao; o que resulta que vai ser impresso um
nmero negativo, 32767 (ou, como comum em vrios compiladores, 32768). A lgica disto tem a ver com
a maneira como o computador guarda nmeros negativos. Mas tambm podemos fazer uma analogia com as
horas. Imaginemos que vamos somar 6 horas com 7 horas. O resultado seria 13, mas como no existe 13 no
relgio, iramos dar a volta nas horas e chegar ao 1. Assim o resultado ser 1.
Caso 5: underflow declaramos um short e colocamos um valor inferior ao mnimo possvel.
Aqui temos exatamente a mesma lgica do caso de overflow, mas desta vez excedido o limite inferior e no
o superior.
Caso 6: declaramos um unsigned int e colocamos um nmero negativo
O que acontece aqui semelhante a um underflow. Mas o que ocorre que o nmero guardado como seria se
fosse um int comum, negativo. O que muda na prtica a interpretao desse nmero, de acordo com o tipo
de dado que lhe est atribudo. Se tentarmos l-lo como um unsigned int, obteremos um valor positivo
obtido pela mesma lgica do overflow/underflow; se o lermos como um (signed) int, obteremos o mesmo
valor negativo que lhe atribumos.
Tipos de dados
19
Converter um tipo de varivel
A converso de uma varivel consiste em converter o tipo de uma varivel em um outro. Imagine que voc esteja
trabalhando com uma varivel do tipo float e por alguma razo queira eliminar os nmeros que esto depois da
vrgula.
Esta operao pode ser realizada de duas maneiras.
Converses do tipo implcita: Consiste em uma modificao do tipo de varivel que feita automaticamente pelo
compilador.
Ex:
int x;
x = 7.123;
Converses do tipo explcita: Tambm chamada de operao cast, consiste em forar a modificao do tipo de
varivel usando o operador cast "( )".
Ex:
int y;
y = (int)7.123;
Veja um exemplo da converso de tipo inteiro em caracteres. Aqui convertemos um numero decimal em um
caractere ASCII.

#include <stdio.h>
int main(void)
{
int y = 65;
char x;
x = (char) y;
printf("O numero inteiro: %d \n O caractere: %c \n\n", y, x);
}
Literais
Em programao, um literal uma notao que representa um valor constante. Exemplos de literais em C so 415,
19.52, 'C', "Joo". Esses exemplos representam os quatro tipos de literais em C: literais de inteiros, literais de reais,
literais de caracteres e literais de strings. S com esses exemplos j possvel deduzir como se usam os literais; mas
importante fazer algumas observaes:
Literais de inteiros podem ser especificados nas bases decimal, octal ou hexadecimal. Se o literal for prefixado
com "0x" ou "0X", ele ser interpretado como hexadecimal; se o prefixo for apenas "0", ser interpretado como
octal; ou se no houver prefixo, ser interpretado como decimal.
Literais de reais podem ser especificados na forma decimal (144.57) ou em notao cientfica (1.4457e+2).
Lembre-se que o separador decimal o ponto e no a vrgula, como seria usual.
Literais de caracteres devem vir entre aspas simples (') e conter a representao de apenas um caractere
1
. Usos
vlidos seriam: 'c', '\n', '\x1b', '\033'. Se voc quiser usar a aspa simples como caractere, preceda-a com uma barra
invertida: '\''.
Tipos de dados
20
Literais de strings devem vir entre aspas duplas ("). Para usar aspas duplas dentro de strings, preceda-as com barra
invertida: "Ele disse \"Ol\".". Note que um literal de string adiciona o caractere nulo (\0) ao final da
string, pois ele , em C, a maneira de delimitar o final de uma string.
Na verdade, segundo o padro C, literais de caracteres podem conter a representao de mais um caractere, mas o
uso deles seria para representar nmeros e no sequncias de caracteres; um aspecto pouco utilizado da linguagem
C.
Constantes
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Constantes
Em um captulo anterior abordamos as variveis e agora vamos abordar constantes. A razo que as coisas esto
mais maduras e uma pessoa sabe muito bem o que uma constante. Que simplesmente um valor que no se altera
durante a execuo do programa. A questo de no se alterar durante a escrita do programa realmente a razo deste
captulo. Devemos separar as guas entre uma constante e um literal. O literal o prprio valor.
Existem 3 maneiras para criar constantes:
1. 1. #define
2. 2. [const] [tipo da varivel][nome da varivel]
3. 3. enumerations
Esta ltima vamos deixar para mais tarde, pois so uma boa introduo para as classes.
DEFINED CONSTANTS (#DEFINE)
#define PI 3.14159265
#define NEWLINE "\n"
Se colocarmos estas linhas no header, o que vai acontecer o seguinte: O pr-processador ir verificar o nosso
cdigo fonte e sempre que encontrar a diretiva #define ir, literalmente, substituir cada ocorrncia do identificador
no cdigo fonte pelo valor definido.
A vantagem disto que:
Podemos ter um identificador ao nosso gosto, e sempre que necessitarmos do valor escrevemos o identificador,
em vez do valor, at porque se o valor fosse complicado poderamos enganar-nos a escrever. Claro que nos
poderamos enganar tambm a escrever o identificador, da a escolhermos um nome familiar.
E se necessitarmos de alterar o valor, alteramos apenas 1 vez, em vez de todas as vezes onde apareceria o valor.
O formato geral :
#define identificador valor
Repare que a diretiva de preprocessador no tem o ;- ponto e vrgulano fim! O que normal para diretivas de
Preprocessador.
O que que acontece se tivermos o ;no fim? Ser que encontrei um bug? se eu colocar o ; no #define NEWLINE
'\n'; no acontece nada.
Constantes
21
Vale lembrar que cada #define preprocessador, ou seja, no pode ser alterado dentro do programa durante sua
execuo.
// defined constants: calculate circumference
#include <stdio.h>
#define PI 3.14159
#define NEWLINE "\n"
int main (){
double r=5.0; // radius
double circle;
circle = 2 * PI * r; // utilizamos o Pi e no 3.
printf("%f", circle);
printf("%s", NEWLINE );
return 0;
}
Declared constants (const)
Ns podemos transformar uma varivel numa constante do gnero:
const int tamanho = 100;
const char tabul = '\t';
const int codigo = 12440;
Com o prefixo "const", dizemos que a varivel no poder alterar o seu valor.
Repare que se fosse uma varivel eu poderia ter:
int a=5;
e logo a seguir dizer
a=6;
e o valor do a ficava com o valor de 6;
Agora com o prefixo const eu no poderei alterar o valor, porque constante constante, no pode mudar o valor.
Esta maneira bem melhor do que a anterior para declarar constantes, primeiro porque aqui temos a informao do
tipo de varivel, em segundo porque podemos fazer este const int a; como uma funo local e no global.
Entrada e sada simples
22
Entrada e sada simples
Entrada e sada simples
Se voc pensar bem, perceber que um computador praticamente intil se no tiver nenhuma maneira de interagir
com o usurio. Por exemplo, se voc abrir um processador de texto, nada ir acontecer at que voc abra um arquivo
ou digite algum texto no teclado. Mas, da mesma maneira, necessrio que o computador fornea informao
tambm: como voc poderia saber se uma tarefa foi concluda?
As trocas de informao entre o computador e o usurio so chamadas entrada e sada (input e output, em ingls).
Entrada a informao fornecida a um programa; sada a informao fornecida pelo programa. comum
referir-se aos dois termos simultaneamente: entrada/sada ou E/S (I/O, em ingls).
Frequentemente so usados os termos "sada padro" (standard output, stdout) e "entrada padro" (standard input,
stdin). Eles se referem, na maioria das vezes, ao monitor e ao teclado, que so os meios bsicos de interao com o
usurio. No entanto, os sistemas operacionais permitem redirecionar a sada e a entrada de programas para outros
dispositivos ou arquivos.
As funes de entrada e sada na linguagem C trabalham com fluxos (streams, em ingls) de dados, que so uma
forma de abstrao de dados de maneira sequencial. Assim, toda entrada e sada feita da mesma maneira, com as
mesmas funes, no importando o dispositivo com o qual estamos nos comunicando (teclado, terminal, arquivo,
etc.). As mesmas funes que descrevem o acesso aos arquivos podem ser utilizadas para se acessar um
terminal de vdeo.
Em C, as funes da biblioteca padro para entrada e sada esto declaradas no cabealho stdio.h. Uma delas j foi
introduzida em sees anteriores: printf(). A seguir daremos mais detalhes sobre essa funo e introduziremos
outras.
puts() e putchar()
puts significa "put string" (colocar string), utilizado para "colocar" uma string na sada de dados. putchar significa
"put char" (colocar caractere), utilizado para "colocar" um caractere na sada de dados.
So as funes mais simples do cabealho stdio.h. Ambas enviam (ou "imprimem") sada padro os caracteres
fornecidos a elas; putchar() manda apenas um caractere, e puts() manda uma sequncia de caracteres (ou
string). Exemplo:
puts ("Esta uma demonstrao da funo puts.");
putchar ('Z');
Note que junto com a funo puts devemos usar literais de string (com aspas duplas), e com putchar devemos
usar literais de caractere (com aspas simples). Se voc tentasse compilar algo como putchar ("T"), o
compilador daria uma mensagem de erro. Lembre-se que "T" diferente de 'T'.
Podemos tambm colocar caracteres especiais, como a tabulao (\t) e a quebra de linha (\n):
puts ("Primeira linha\nSegunda linha\te um grande espao");
putchar ('\n'); // apenas envia uma quebra de linha
Este cdigo resultaria em algo parecido com:
Primeira linha
Segunda linha e um grande espao
Entrada e sada simples
23
Observe que a funo puts() sempre coloca uma quebra de linha aps imprimir a string. J com as funes
putchar() e printf() (vista a seguir), isso no ocorre. O cdigo abaixo, por exemplo:
putchar('c');
putchar('h');
putchar('\n');
puts("String.");
puts("Outra string.");
imprimiria algo parecido com isto:
ch
String.
Outra string.
Observe que os caracteres 'c' e 'h' so exibidos na mesma linha, pois no foi inserida uma quebra de linha entre eles.
J as strings "String." e "Outra string." so exibidas em linhas diferentes, pois a funo puts() insere uma quebra de
linha aps cada string, mesmo que no haja um caractere '\n' nas literais de string do cdigo.
Os outros caracteres especiais so introduzidos adiante.
Note que o argumento deve ser uma sequncia de caracteres. Se voc tentar, por exemplo, imprimir o nmero 42
desta maneira:
puts(42);
Na verdade o que o compilador tentar fazer imprimir a sequncia de caracteres que comea na posio 42 da
memria (provavelmente ele ir alert-lo sobre isso se voc tentar compilar esse cdigo). Se voc tentar executar
esse cdigo, provavelmente ocorrer uma falha de segmentao (erro que ocorre quando um programa tenta acessar
memria que no lhe pertence). A maneira correta de imprimir o nmero 42 seria coloc-lo entre aspas duplas:
puts("42");
printf()
printf vem de "print formatted" (imprimir formatado).
primeira vista, a funo printf() pode parecer idntica puts(). No entanto, ela muito mais poderosa. Ela permite
facilmente imprimir valores que no so sequncias de caracteres, alm de poder formatar os dados e juntar vrias
sequncias de caracteres. Por isso, a funo printf() muito mais usada que a puts().
Ela pode ser usada exatamente como a funo puts(), se fornecermos a ela apenas uma sequncia de caracteres:
printf("Este um programa em C");
Ela tambm pode ser escrita da seguinte forma:
printf("Ola"
" mundo"
"!!!" );
Mas e se precisarmos imprimir o contedo de uma varivel? A funo printf tambm pode fazer isso! Voc
deve, obviamente, especificar onde o valor da varivel deve ser impresso. Isso feito atravs da especificao de
formato %d, caso a varivel seja do tipo int (sequncias para outros tipos sero dadas adiante). Voc tambm
precisar, logicamente, especificar qual varivel imprimir. Isso feito dando-se mais um argumento funo
printf(). O cdigo dever ficar assim:
Entrada e sada simples
24
int teste;
teste = 42;
printf ("A varivel 'teste' contm o nmero %d.", teste);
Tendo colocado isso no seu programa, voc dever ver na tela:
A varivel 'teste' contm o nmero 42.
Vamos supor que voc queira imprimir um nmero no inteiro. Voc teria que trocar "%d" por %f. Exemplo:
float pi;
pi = 3.1415;
printf ("O valor de pi %f.", pi);
O cdigo acima ir retornar:
O valor de pi 3.1415.
Voc pode imprimir quantos valores quiser, bastando para isso colocar mais argumentos e mais especificaes de
formato, lembrando de colocar na ordem certa. Alguns compiladores, como o gcc, mostram um aviso caso o nmero
de argumentos seja diferente do nmero de especificaes de formato, o que provavelmente causaria resultados
indesejados. A sintaxe geral da funo printf() :
printf ("string de formatao", arg1, arg2, ...);
Suponha que voc tem um programa que soma dois valores. Para mostrar o resultado da conta, voc poderia fazer
isso:
int a, b, c;
... // leitura dos dados
c = a + b; // c o resultado da soma
printf ("%d + %d = %d", a, b, c);
O que resultaria em, para a = 5 e b = 9:
5 + 9 = 14
A seguir mostramos os especificadores de formato para vrios tipos de dados.
Especificaes de formato
A documentao mais tcnica os chama de "especificadores de converso", pois o que ocorre na maioria das vezes ,
de fato, a converso de um valor numrico em uma sequncia de caracteres que representa aquele valor. Mas o nome
"formato" no deixa de estar correto, pois eles especificam em que formato (inteiro, real etc.) est o argumento
correspondente.
Entrada e sada simples
25
Cdigo Converso/Formato do argumento
%d Nmero decimal inteiro (int). Tambm pode ser usado %i como equivalente a %d.
%u Nmero decimal natural (unsigned int), ou seja, sem sinal.
%o Nmero inteiro representado na base octal. Exemplo: 41367 (corresponde ao decimal 17143).
%x Nmero inteiro representado na base hexadecimal. Exemplo: 42f7 (corresponde ao decimal 17143). Se usarmos %X, as letras sero
maisculas: 42F7.
%X Hexadecimal com letras maisculas
%f Nmero decimal de ponto flutuante. No caso da funo printf, devido s converses implcitas da linguagem C, serve tanto para float
como para double. No caso da funo scanf, %f serve para float e %lf serve para double.
%e Nmero em notao cientfica, por exemplo 5.97e-12. Podemos usar %E para exibir o E maisculo (5.97E-12).
%E Nmero em notao cientfica com o "e"maisculo
%g Escolhe automaticamente o mais apropriado entre %f e %e. Novamente, podemos usar %G para escolher entre %f e %E.
%p Ponteiro: exibe o endereo de memria do ponteiro em notao hexadecimal.
%c Caractere: imprime o caractere que tem o cdigo ASCII correspondente ao valor dado.
%s Sequncia de caracteres (string, em ingls).
%% Imprime um %
Observao Se voc quiser imprimir um sinal de porcentagem, use %%. Exemplo:
printf("O lucro para o ltimo ms foi de 20%%.");
Numa sequncia de controle, possvel tambm indicar a largura do campo, o nmero de casas decimais, o tamanho
da varivel e algumas opes adicionais. O formato geral :
%[opes][largura do campo][.preciso][tamanho da varivel]tipo de dado
A nica parte obrigatria o tipo de dado. Todas as outras podem ser omitidas.
Opes
As opes so parmetros opcionais que alteram a formatao. Voc pode especificar zero ou mais delas,
colocando-as logo aps o sinal de porcentagem:
0: o tamanho do campo deve ser preenchido com zeros esquerda quando necessrio, se o parmetro
correspondente for numrico.
- (hfen): o valor resultante deve ser alinhado esquerda dentro do campo (o padro alinhar direita).
(espao): no caso de formatos que admitem sinal negativo e positivo, deixa um espao em branco esquerda de
nmeros positivos.
+: o sinal do nmero ser sempre mostrado, mesmo que seja positivo.
' (aspa simples/apstrofe): nmeros decimais devem ser exibidos com separador de milhares caso as
configuraes regionais o especifiquem. Essa opo normalmente s funciona nos sistemas Unix.
Entrada e sada simples
26
Largura do campo
Como o prprio nome j diz, especifica qual a largura mnima do campo. Se o valor no ocupar toda a largura do
campo, este ser preenchido com espaos ou zeros. Por exemplo, podemos imprimir um cdigo de at 5 dgitos
preenchido com zeros, de maneira que os valores 1, 27, 409 e 55192 apaream como 00001, 00027, 00409 e 55192.
A largura deve ser especificada logo aps as opes, se presentes, e pode ser um nmero que especifica a largura
ou um asterisco, que diz que a largura ser especificada pelo prximo argumento (ou seja, o argumento anterior
ao valor a ser impresso). Neste exemplo, o campo ter largura igual ao valor de num e o valor impresso ser 300:
printf ("%*d", num, 300);
O campo impresso de acordo com as seguintes regras:
Se o valor for mais largo que o campo, este ser expandido para poder conter o valor. O valor nunca ser cortado.
Se o valor for menor que o campo, a largura do campo ser preenchida com espaos ou zeros. Os zeros so
especificados pela opo 0, que precede a largura.
O alinhamento padro direita. Para se alinhar um nmero esquerda usa-se a opo - (hfen ou sinal de
menos) antes da largura do campo.
Por exemplo, compare as trs maneiras de exibir o nmero 15:
printf ("%5d", 15); // exibe " 15"
printf ("%05d", 15); // exibe "00015"
printf ("%-5d", 15); // exibe "15 "
E alguns outros exemplos:
printf ("%-10s", "Jos"); // exibe "Jos "
printf ("%10s", "Jos"); // exibe " Jos"
printf ("%4s", "Jos"); // exibe "Jos"
Preciso
A preciso pode ter quatro significados diferentes:
Se a converso solicitada for inteira (d, i, o, u, x, X): o nmero mnimo de dgitos a exibir (ser preenchido com
zeros se necessrio).
Se a converso for real (a, A, e, E, f, F): o nmero de casas decimais a exibir. O valor ser arredondado se a
preciso especificada no formato for menor que a do argumento.
Se a converso for em notao cientfica (g, G): o nmero de algarismos significativos. O valor ser arredondado
se o nmero de algarismos significativos pedido for maior que o do argumento.
Se a converso for de uma sequncia de caracteres (s): o nmero mximo de caracteres a exibir.
Assim como a largura do campo, a preciso pode ser especificada diretamente por um nmero ou com um asterisco,
mas deve ser precedida por um ponto.
Alguns exemplos:
printf ("%.5d", 314); // exibe "00314"
printf ("%.5f", 2.4); // exibe "2.40000"
printf ("%.5g", 23456789012345); // exibe "2.3457e+13"
printf ("%.5s", "Bom dia"); // exibe "Bom d"
claro que podemos combinar a largura com a preciso. Por exemplo, %10.4f indica um campo de nmero real de
comprimento total dez e com 4 casas decimais. Note que, na largura do campo, o valor inteiro levado em conta,
inclusive o ponto decimal, e no apenas a parte inteira. Por exemplo, essa formatao aplicada ao nmero 3.45 ir
Entrada e sada simples
27
resultar nisto:
" 3.4500"
Tamanho da varivel
importante ressaltar que quando so usados modificadores de tamanho de tipos, a maneira como os dados so
armazenados pode tornar-se diferente. Assim, devemos informar funo printf() precisamente qual o tipo da
varivel cujo valor desejamos exibir. A funo printf() admite cinco principais modificadores de tamanho de
varivel:
hh: indica que a converso inteira corresponde a uma varivel char. Por exemplo, poderamos usar o formato
%hhd para exibir uma varivel do tipo char na base decimal.
h: indica que a converso inteira corresponde a uma varivel short.
l: indica que a converso inteira corresponde a uma varivel long.
ll: indica que a converso inteira corresponde a uma varivel long long.
L: indica que a converso de nmero real corresponde a uma varivel long double.
Quando o tipo da varivel no tem modificadores de tamanho (long ou short), no se usa nenhum modificador
de tamanho da varivel na funo printf().
Sequncias de escape
Sequncias de escape so combinaes de caracteres que tm significado especial, e so sempre iniciadas por uma
barra invertida (\). Voc pode us-las em qualquer literal de caractere ou string. Por exemplo, a string "linha
1\nlinha 2" equivale a:
linha 1
linha 2
pois a sequncia \n indica uma quebra de linha. Como foi citado anteriormente, a funo printf(),
diferentemente de puts(), no imprime automaticamente uma quebra de linha no final da string. O cdigo abaixo,
por exemplo:
printf("string 1");
printf("string 2");
Imprimiria isto:
string 1string 2
Isso pode ser til, pois s vezes desejvel permanecer na mesma linha.
A seguir apresentamos a tabela com as sequncias de escape suportadas pela linguagem C:
Entrada e sada simples
28
Sequncia Significado
\n Quebra de linha (line feed ou LF)
\t Tabulao horizontal
\b Retrocede o cursor em um caractere (backspace)
\r Retorno de carro (carriage return ou CR): volta o cursor para o comeo da linha sem mudar de linha
\a Emite um sinal sonoro
\f Alimentao de formulrio (form feed ou FF)
\v Tabulao vertical (em impressoras)
\" Aspa dupla
\' Aspa simples
\\ Barra invertida
\0 Caractere nulo (caractere de valor zero, usado como terminador de strings)
\N O caractere cuja representao octal N (dgitos de 0 a 7)
\xN O caractere cuja representao hexadecimal N (dgitos de 0 a 9 e de A a F)
Representao octal e hexadecimal
Tambm possvel trocar uma sequncia de escape pelo seu valor em octal ou hexadecimal. Voc pode, por
exemplo, trocar o caractere "\n" pelo valor octal "\12" ou hexadecimal "\x0A". Vejamos mais alguns exemplos.
Hexadecimal Octal Caracter
\x00 \00 \0
\x0A \12 \n
\x0D \15 \r
\x07 \07 \a
\x08 \10 \b
\x0B \13 \v
scanf()
A funo scanf() l dados da entrada padro (teclado) e os guarda em variveis do programa. Assim como para
printf(), usamos uma string de formatao para especificar como sero lidos os dados. A sintaxe de scanf() esta:
scanf ("string de formatao", &arg1, &arg2, ...);
Como voc pode ver, a sintaxe quase igual de printf(), com exceo do E comercial (&). Voc entender melhor
o seu uso nas sees seguintes, mas adiantamos que ele um operador que retorna o endereo de uma varivel. Isso
necessrio pois a funo scanf() deve modificar as variveis, e quando no usamos o operador de endereo,
passamos apenas o valor de uma varivel para a funo. Isso ser explicado melhor no captulo sobre ponteiros. O
fato de scanf receber endereos de variveis (em vez de seus valores) tambm explica por que ele precisa ser
informado da diferena entre %f (float) e %lf (double) enquanto que o printf no precisa.
Um exemplo bsico da utilizao de scanf() este:
int a;
scanf ("%d", &a);
Entrada e sada simples
29
O que este exemplo faz declarar uma varivel e aguardar o usurio digitar algo. Os dados s sero processados
quando o usurio apertar Enter. Depois disso, os caracteres digitados pelo usurio sero convertidos para um valor
inteiro e esse inteiro ser guardado no endereo que corresponde varivel a. Se o valor digitado no puder ser
convertido (porque o usurio no digitou nenhum algarismo vlido), a varivel no ser modificada.
Assim como na funo printf(), podemos receber quantos valores quisermos, bastando usar vrios especificadores de
converso:
int a;
char b;
float c;
scanf ("%d %c %f", &a,&b,&c);
Dessa maneira, se o usurio digitar 120 z 17.63, teremos a igual a 120, b igual ao caractere 'z' e c igual ao
nmero 17,63. Se o usurio tentar digitar mais de um espao entre os dados ou simplesmente nenhum espao, ainda
assim o programa obter os dados certos. Por exemplo, 120z17.63 tambm dar o mesmo resultado.
Agora uma questo um pouco mais difcil: vamos supor que especificamos um formato inteiro e o usurio digitou
um nmero real, como por exemplo 12.5. O que dever acontecer?
#include <stdio.h>
int main ()
{
int a;
printf ("Digite um nmero: ");
scanf ("%d", &a);
printf ("\nO nmero digitado foi %d", a);
return (0);
}
Se voc testar com o valor 12.5, vai ver que o programa retornar o nmero 12, pois a funo scanf() apenas
interpreta os caracteres vlidos para aquele formato.
Os especificadores de converso so praticamente os mesmos que os da funo printf(), com algumas mudanas. A
maioria deles pula espaos em branco, exceto dois.
%i no mais sinnimo de %d. O que %i faz interpretar o valor digitado como hexadecimal, se iniciar-se por
0x ou 0X; como octal, se iniciar-se por 0; ou como decimal, caso nenhuma dessas condies seja verificada.
%a, %e/%E e %g so sinnimos de %f.
%lf deve ser usado para variveis do tipo double.
%s l uma sequncia de caracteres no-brancos (qualquer caractere exceto espao, tabulao, quebra de linha
etc.), ou seja, uma palavra.
%c l uma sequncia de caracteres, sem ignorar espaos. O padro ler um caractere, se no for especificada a
largura do campo.
%[...] l uma sequncia de caracteres, sem ignorar espaos, especificando entre colchetes quais caracteres
devem ser aceitos, ou, se o primeiro caractere dentro dos colchetes for um acento circunflexo (^), quais no
devem ser aceitos. Alm disso, se colocarmos um trao entre dois caracteres, todos os caracteres entre os dois
sero includos no padro. Por exemplo, se quisermos incluir qualquer letra minscula, poderimos escrever
%[a-z]; se quisssemos tambm incluir as maisculas, colocaramos %[a-zA-Z]. A leitura pra quando for
Entrada e sada simples
30
encontrado um caractere que no coincide com o padro especificado.
J os modificadores funcionam de maneira bastante diferente:
O modificador * (asterisco) especifica que o valor atual deve ser lido da maneira especificada, mas no ser
guardado em nenhuma varivel, e portanto no deve haver um ponteiro correspondente a esse valor. Por exemplo,
poderimos ter um programa que espera ler uma palavra e depois um nmero, mas no importa qual palavra .
Nesse caso usaramos o modificador *: scanf ("%*s %d", &numero). O programa leria a palavra e
guardaria o nmero na varivel numero.
Como na funo printf(), existe o especificador de largura do campo, que deve aparecer antes do especificador de
converso, mas em scanf() ele especifica a largura mxima. Se a largura mxima foi definida como n, scanf()
pular para o prximo campo se j tiver lido n caracteres. Por exemplo, scanf ("%4d", &num) ler um
nmero de at quatro algarismos. Se o usurio digitar mais, o excedente ser no ser lido por essa chamada, mas
poder ser lido por uma prxima chamada a scanf.
Mais detalhes sobre os especificadores de converso e os modificadores podem ser encontrados na documentao da
biblioteca padro.
Valor de retorno
A funco scanf() retorna o nmero de converses realizadas com sucesso. Isso til pois, se o valor contido
numa varivel aps a chamada de scanf() for igual ao valor anterior, no possvel saber se o valor digitado foi o
mesmo que j havia ou se no foi feita a converso. Para obter esse nmero de converses realizadas, voc deve
guardar o resultado numa varivel do tipo int. Veja como proceder:
int a, b;
int num;
num = scanf("%d%d", &a, &b);
Este exemplo l dois nmeros inteiros e os guarda nas variveis a e b. O nmero de converses realizadas
guardado na varivel num. Se aps o scanf, num for diferente de 2, sinal de que o usurio digitou algo
incompatvel com o formato desejado.
Note que aqui introduzimos um conceito novo: o valor de retorno de uma funo. Ele pode ser obtido simplesmente
associando o valor de uma varivel chamada da funo. Ele ser detalhado na seo Funes, mas j possvel
compreender um pouco sua utilizao.
gets() e getchar()
gets() e getchar(), assim como scanf(), lem da entrada padro. Assim como puts() e putchar(), no
suportam formatao. Como o nome sugere, getchar() l apenas um caractere, e gets() l uma string at o
final da linha ou at que no haja mais dados para ler, e adiciona o terminador de string "\0".
A sintaxe das funes :
gets(ponteiro_para_string);
char c;
c = getchar();
No entanto, existe um problema com a funo gets(). Veja o exemplo a seguir:
#include <stdio.h>
int main()
Entrada e sada simples
31
{
char buffer[10];
printf("Entre com o seu nome: ");
gets(buffer);
printf("O nome : %s", buffer);
return 0;
}
A notao char buffer[10], que ainda no foi introduzida (e ser detalhada na seo Vetores (arrays)), pede
que seja reservado um espao para 10 caracteres para a string buffer. Portanto, se usurio digitar mais de 9
caracteres (pois o terminador de string adicionado ao que o usurio digitou), os caracteres excedentes adicionais
sero colocados na rea de memria subsequente ocupada pela varivel, escrevendo uma regio de memria que
no est reservada string. Este efeito conhecido como "estouro de buffer" e pode causar problemas imprevisveis.
Por isso, no se deve usar a funo gets(); mais tarde introduziremos a funo fgets(), que no apresenta esse
problema e que deve ser usada no lugar de gets().
sprintf() e sscanf()
sprintf e sscanf so semelhantes a printf e scanf. Porm, ao invs de escreverem na sada padro ou
lerem da entrada padro, escrevem ou lem em uma string. A nica mudana nos argumentos a necessidade de
especificar a string que deve ser lida ou atribuda no incio. Veja os exemplos para entender melhor.
#include <stdio.h>
int main()
{
int i;
char string1[30];
printf("Entre um valor inteiro: ");
scanf("%d", &i);
sprintf(string1, "Valor de i = %d", i);
puts(string1);
return 0;
}
Nesse exemplo, a mensagem que queramos exibir na tela foi primeiramente salva em uma string, e depois essa
string foi enviada para a tela. Se voc olhar bem, se voc tivesse alocado um valor menor para string1, tambm
ocorreria um estouro de buffer. Para evitar esse problema, existe a funo snprintf, que tem mais um argumento:
o tamanho da string (deve ser colocado depois da string onde a mensagem ser gravada).
#include <stdio.h>
int main()
{
int i, j, k;
char string1[] = "10 20 30";
sscanf(string1, "%d %d %d", &i, &j, &k);
printf("Valores lidos: %d, %d, %d", i, j, k);
return 0;
}
Entrada e sada simples
32
Nesse exemplo, usamos a funo sscanf para interpretar os valores contidos na string e guard-los nas variveis
numricas.
Operaes matemticas (Bsico)
Operaes matemticas
Em C, fazer operaes matemticas simples bastante fcil e intuitivo. Por exemplo, se quisermos que uma varivel
contenha o resultado da conta 123 + 912, fazemos assim:
var = 123 + 912;
Os operadores aritmticos bsicos so 5: + (adio), - (subtrao), * (multiplicao), / (diviso) e % (resto de diviso
inteira).
Outro exemplo:
int a = 15;
int b = 72;
int c = a * b; /* c valer 1572 */
Podemos usar mais de um operador na mesma expresso. A precedncia igual usada na matemtica comum:
a = 2 + 4 * 10; /* retornar 42, o mesmo que (2 + (4 * 10)) */
a = 2 + 40 / 2 + 5; /* retornar 27, o mesmo que (2 + (40 / 2) + 5) */
Voc pode usar parnteses, como em expresses matemticas normais:
a = (2 + 4) * 10; /* retornar 60 */
a = (2 + 40) / (2 + 5); /* retornar 6 */
Note que uma operao entre nmeros inteiros sempre retornar um nmero inteiro. Isso evidente para a adio,
subtrao e multiplicao. Mas em uma diviso de inteiros, por exemplo 3/2, a expresso retornar apenas a parte
inteira do resultado, ou seja, 1.
Se quisermos um resultado no-inteiro, um dos operandos deve ser no-inteiro. Nesse exemplo, poderamos usar
3.0/2 ou 3/2.0, ou mesmo 3./2 ou (1.0 * 3)/2, pois, em C, uma operao envolvendo um nmero
no-inteiro sempre ter como resultado um nmero real.
Note que em C o separador decimal o ponto e no a vrgula.
O seguinte exemplo poderia surpreender, pois o programa dir que o valor de f continua sendo 3.
#include <stdio.h>
int main()
{
int i = 5;
int j = 2;
float f = 3.0;
f = f + j / i;
printf("O valor de f %f", f);
return 0;
}
Operaes matemticas (Bsico)
33
Mas, segundo a precedncia dos operadores, j / i deveria ser calculado primeiro, e como ambos os valores so
do tipo inteiro, o valor dessa expresso zero.
importante que voc grave um arquivo .c com o cdigo acima e execute usando o compilador para ver o
funcionamento com os prprios olhos.
Abreviaes
Alguns tipos de atribuies so bastante comuns, e por isso foram criadas abreviaes. Por exemplo, muito comum
incrementar em uma unidade o valor de uma varivel (em loops, por exemplo). Em vez de escrever var = var +
1, podemos escrever simplesmente var++. Da mesma maneira, existe o operador de decremento, que decrementa
em uma unidade o valor da varivel: var-- (equivalente a var = var - 1).
Os operadores de decremento e incremento tambm podem ser utilizados antes do nome da varivel. Isso significa
que estas duas instrues so equivalentes:
var++;
++var;
Agora vamos supor que voc use em seu programa uma varivel que aumenta de 10 em 10 unidades. claro que
usar var++ dez vezes no abreviaria nada. Em vez disso, existe a abreviao var += 10.
Genericamente, para qualquer dos cinco operadores aritmticos op, vale a abreviao:
var = var op num;
var op= num;
Ou seja, os seguintes pares so equivalentes:
x *= 12; x = x * 12;
x /= 10; x = x / 10;
x -= 2; x = x - 2;
x %= 11; x = x % 11;
Este exemplo clarifica o uso dos operadores de incremento:
#include <stdio.h>
int main()
{
int a, b;
a = b = 5;
printf("%d\n", ++a + 5);
printf("%d\n", a);
printf("%d\n", b++ + 5);
printf("%d\n", b);
return 0;
}
O resultado que voc deve obter ao executar o exemplo :
11
6
10
6
Operaes matemticas (Bsico)
34
Esse resultado mostra que ++var e var++ no so a mesma coisa se usados como uma expresso. Quando
usamos os operadores na forma prefixal (antes do nome da varivel), o valor retornado depois de ser incrementado;
na forma sufixal, o valor retornado e depois incrementado. O mesmo vale para o operador de decremento.
E o que aconteceria se voc escrevesse algo como o seguinte?
printf("%d\n", a / ++a);
A resposta : no sabemos. Segundo o padro C, o resultado disso indefinido (o que significa que pode variar de
um compilador para outro). No existe uma regra sobre avaliar primeiro o numerador ou o denominador de uma
frao. Ou seja, no use uma varivel mais de uma vez numa expresso se usar operadores que a modificam.
Talvez voc tenha achado estranha a linha:
a = b = 5;
Isso possvel porque atribuies so feitas da direita para a esquerda e uma instruo de atribuio tambm uma
expresso que retorna o valor atribudo. Ou seja, a expresso b = 5 retornou o valor 5, que foi usado pela
atribuio a = (b = 5), equivalente a a = 5.
Operaes matemticas (Avanado)
O cabealho <math.h> contm prottipos de algumas funes na rea de matemtica. Na verso de 1990 do
padro ISO, somente a verso double das funes foram especficadas; na verso de 1999 foram adicionadas as
verses float e long double.
As funes podem ser agrupadas nas seguintes categorias:
1. 1. Funes Trigonomtricas
2. 2. Funes Hiperblicas
3. 3. Funes Exponencial e Logaritmo
4. 4. Funes pow e sqrt
5. 5. Funes de Arredondamento para Nmeros Inteiros, Valores Absolutos e Resto da Diviso
Funes Trigonomtricas
As funes acos e asin
A funo acos retorna o arco-cosseno dos seus argumentos em radianos, e a funo asin retorna o arco-seno dos
seus argumentos em radianos. Todas as funes esperam por argumentos que estejam no intervalo [-1,+1]. O
arco-cosseno retorna valores no intervalo [0,]; o arco-seno retorna valores no intervalo [-/2,+/2].
#include <math.h>
float asinf(float x); /* C99 */
float acosf(float x); /* C99 */
double asin(double x);
double acos(double x);
long double asinl(long double x); /* C99 */
long double acosl(long double x); /* C99 */
Operaes matemticas (Avanado)
35
As funes atan e atan2
As funes atan retornam o arco-tangente dos arguments em radianos, e a funo atan2 retorna o arco-tangente
de y/x em radianos. As funes atan retornam o valor no intervalo [-/2,+/2] (a razo pelo que /2 est
incluido no intervalo porque os valores decimais pode representar o infinito, e atan() = /2); as funes
atan2 retornam o valor no intervalo [-,+]. Para a funo atan2, um "domain error" pode ocorrer se os dois
argumentos forem zero.
#include <math.h>
float atanf(float x); /* C99 */
float atan2f(float y, float x); /* C99 */
double atan(double x);
double atan2(double y, double x);
long double atanl(long double x); /* C99 */
long double atan2l(long double y, long double x); /* C99 */
As funes cos, sin e tan
As funes cos, sin, e tan retornam o coseno, seno, e tangente do argumento, expresso em radianos.
#include <math.h>
float cosf(float x); /* C99 */
float sinf(float x); /* C99 */
float tanf(float x); /* C99 */
double cos(double x);
double sin(double x);
double tan(double x);
long double cosl(long double x); /* C99 */
long double sinl(long double x); /* C99 */
long double tanl(long double x); /* C99 */
Funes Hiperblicas
As funes cosh, sinh and tanh computam o coseno hiperblico, o seno hiperblico e a tangente hiperblica
respectivamente. Para as funes de seno e coseno hiperblico, um erro de ...
#include <math.h>
float coshf(float x); /* C99 */
float sinhf(float x); /* C99 */
float tanhf(float x); /* C99 */
double cosh(double x);
double sinh(double x);
double tanh(double x);
long double coshl(long double x); /* C99 */
long double sinhl(long double x); /* C99 */
long double tanhl(long double x); /* C99 */
Operaes matemticas (Avanado)
36
Funes Exponencial e Logaritmo
A funo exp
As funes exp computam a funo exponencial de x (e
x
). Um "range error" ocorre se o valor de x muito
grande.
#include <math.h>
float expf(float x); /* C99 */
double exp(double x);
long double expl(long double x); /* C99 */
As funes frexp, ldexp e modf
As funes frexp dividem um nmero real numa frao normalizada e um nmero inteiro mltiplo de 2. As
funes guardam o nmero inteiro no objeto apontado por ex.
As funes frexp retornam o valor x de forma que x tem o valor [1/2, 1) ou zero, e value igual a x vezes 2
elevado a *ex. Se value for zero, as duas partes do resultado seram zero.
As funes ldexp multiplicam um nmero real por um nmero inteiro mltiplo de 2 e retornam o resultado. Um
"range error" pode ocorrer.
As funes modf divide o argumento value entre um parte inteira e uma frao, cada uma tem o mesmo sinal do
argumento. As funes guardam o parte inteira no objeto apontado por *iptr e retornam o frao.
#include <math.h>
float frexpf(float value, int *ex); /* C99 */
double frexp(double value, int *ex);
long double frexpl(long double value, int *ex); /* C99 */
float ldexpf(float x, int ex); /* C99 */
double ldexp(double x, int ex);
long double ldexpl(long double x, int ex); /* C99 */
float modff(float value, float *iptr); /* C99 */
double modf(double value, double *iptr);
long double modfl(long double value, long double *iptr); /* C99 */
As funes log e log10
As funes log computam o logaritmo natural do argumento e retornam o resultado. Um "domain error" ocorre se
o argumento for negativo. Um "range error" pode ocorrer se o argumento for zero.
As funs log10 computam o logaritmo comum (base-10) do argumento e retornam o resultado. Um "domain
error" ocorre se o argumento for negativo. Um "range error" ocorre se o argumento for zero.
#include <math.h>
float logf(float x); /* C99 */
double log(double x);
long double logl(long double x); /* C99 */
float log10f(float x); /* C99 */
double log10(double x);
long double log10l(long double x); /* C99 */
Operaes matemticas (Avanado)
37
Funes pow e sqrt
As funes pow
As funes pow computam x elevado a y e retornam o resultado. Um "domain error" ocorre se x for negativo e
y no for um nmero inteiro. Um "domain error" ocorre se o resultado no puder ser representado quando x zero e
y menor ou igual a zero. Um "range error" pode ocorrer.
#include <math.h>
float powf(float x, float y); /* C99 */
double pow(double x, double y);
long double powl(long double x, long double y); /* C99 */
As funes sqrt
As funes sqrt computam a raiz positiva de x e retornam o resultado. Um "domain error" ocorre se o argumento
for negativo.
#include <math.h>
float sqrtf(float x); /* C99 */
double sqrt(double x);
long double sqrtl(long double x); /* C99 */
Funes de Arredondamento para Nmeros Inteiros, Valores Absolutos e
Resto da Diviso
As funes ceil e floor
As funes ceil computam o menor nmero inteiro que no seja menor que x e retornam o resultado; as funes
floor computam o maior nmero inteiro que no seja maior que x e retornam o resultado.
#include <math.h>
float ceilf(float x); /* C99 */
double ceil(double x);
long double ceill(long double x); /* C99 */
float floorf(float x); /* C99 */
double floor(double x);
long double floorl(long double x); /* C99 */
As funes fabs
As funes fabs computam o valor absoluto do nmero real x e retornam o resultado.
#include <math.h>
float fabsf(float x); /* C99 */
double fabs(double x);
long double fabsl(long double x); /* C99 */
Operaes matemticas (Avanado)
38
As funes fmod
As funes fmod computam o resto de x/y e retornam o valor x - i * y, pra algum nmero inteiro i onde, se y
for um nmero diferente de zero, o resultado tem o mesmo sinal de x e magnitude menor que a magnitude de y. Se
y for zero, dependendo da implementao da funo, ocorrer um "domain error" ou a funo fmod retornar zero.
#include <math.h>
float fmodf(float x, float y); /* C99 */
double fmod(double x, double y);
long double fmodl(long double x, long double y); /* C99 */
Ligaes externas
Biblioteca de referncia C++ (C++ Reference Library) - cmath (math.h)
[1]
Referncias
[1] http:/ / www. cplusplus. com/ reference/ clibrary/ cmath/
Operadores
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Operadores Aritmticos
Tabela: Operadores aritmeticos
Operador Finalidade Exemplo Resultado
+ Adio 5 + 2 7
- Subtrao 5 2 3
* Multiplicao 5 * 2 10
/ Diviso (Quociente) 5 / 2 2
% Diviso Euclidiana (Resto) 30 % 7 2
Notar o ltimo operador. Notar que so operadores que operam apenas com 2 operandos (operadores binrios).
Na diviso euclidiana temos 30 dividido 7 tem por quociente 4 e como resto 2.
30 / 7 = 4
30 = 7 x 4 + 2
30 % 7 = 2
Existe uma maneira de fazer abreviaturas:
Operadores
39
Expresso Original Expresso equivalente
x=x+k; x+=k;
x=x-k; x-=k;
x=x*k; x*=k;
x=x/k; x/=k;
x=x>>k; x>>=k;
x=x<<k; x<<=k;
x=x&k; x&=k;;
x=x+1 x+=1 ou x++
Isto mais uma abreviatura para os programadores escreverem menos. H quem ache isto muito estpido pois um
esforo de assimilao desnecessrio em troca a escrever uma letra.
Iremos ver que ter a++ ou ++a diferente! Mas isso vai ser na histria dos loops. (iremos ter situaes tipo++a+5
que seria a+5 mas antes fazer a+1+5.)
Mais uma nota. Em relao ao operador adio ele para alm dos nmeros tambm permite adicionar strings, isto ,
junta a segunda string no fim da primeira string. No entanto se juntarmos um dgito com uma string isso j no
permitido.
Precedncia de Operadores aritmticos
Precedncia de operadores aritmticos (o operador aritmtico tem maior precedncia do que o operador de
asignment)
Table 4-3: Prioridade dos operadores aritmticos
Prioridade Operador
Alta (Operador unrio de negao)
Mdia-alta * / %
Normal +
No caso de termos na mesma instruo operadores com o mesmo nvel de precedncia (prioridade) fazer a regra da
esquerda para a direita. eg. a=8/2*4 seria 16 e no 1, porque temos a diviso est no lado esquerdo.
Mais um ponto em relao ao operador %mdulo (modulus). Podemos fazer o mdulo para nmeros inteiros mas
se tentarmos para nmeros do tipo float (ou um deles) fica indefinido. Geralmente resulta num erro de compilao
(mas isso vai depender do compilador)
Notar igualmente overflow de que j falamos (antes e depois de compilar). ou seja pego no valor de uma varivel
adiciono o valor de uma segunda varivel e dou esse resultado a uma terceira varivel. Isto pode resultar em
overflow. Ser trabalho do programador em controlar isto.
O que que resulta se adicionarmos um int por um float e esse float com casas decimais e colocarmos esse resultado
num int? o que resulta que o resultado fica truncado. a mesma situao de declarar um int e colocar um float.
como foi visto no capitulo das variveis.
Operadores
40
type casting
fazer com que o resultado saia com a tipologia desejada.
#include <stdio.h>
int main(void)
{
int firstOp = 10, secondOp = 4;
float result = (float) firstOp / secondOp;
printf("%d / %d = %f\n", firstOp, secondOp, result );
return 0;
}
Neste exemplo estamos a fazer com que o firstOp seja convertido para tipo float, quando antes tnhamos declarado
como um int, ou seja o valor 10 passa a ser 10.0. e agora como temos um float a dividir por um int, o que acontece
que h uma converso automtica, ou seja o 2 int convertido em float, fazendo com que o resultado seja um float
Podemos utilizar qualquer uma das expresses seguintes para exprimir o tycasting.
float result = (float) firstOp / secondOp;
float result = float (firstOp) / secondOp;
float result = firstOp / (float) secondOp;
float result = firstOp / float (secondOp);
Expoentes
O C e o C++ no tm o operador expoente, no entanto, tem a funo pow (de power) que est no cabealho da
biblioteca padro <math.h>. a funo pow() tem 2 argumentos, o primeiro para a base e o 2 para o expoente. o 1
argumento tem de ser float ou double.
Operadores relacionais
Permite fazer comparaes lgicas de ordenao de nmeros, e ainda de letras (mas no strings) Table: Relational
Operators
Operador Significado
> Maior que
< Menor que
>= Maior ou igual
<= Menor ou igual
== Igual a
!= Diferente de
Vo poderia se perguntar: Como que o computador faz essa comparao ? de onde que ele sabe que um nmero
A maior que outro B?
Resposta: Considere que voc quisesse comparar dois dados tipo char, lembrando que um char na verdade um
nmero inteiro na tabela ASCII. Sendo assim suponha que gostarias de comparar o caractere 'a' que igual a 97 na
tabela ascii com o caractere 't' que 116 na tabela; assim, ao comparar 97 com 116 o que acontee na memria a
comparao de 01100001 (97) com 01110100 (116) em um registrador especfico, vo sendo somadas as potncias
de 2 da esquerda para a direita de forma que fica evidente para ele (o registrador) quem maior. Isso o que
acontee quando comparamos duas strings com a funo strcmp e ela retorna um nmero para a diferena entre elas.
Operadores
41
Esse nmero justamente a diferena entre os valores da tabela ASCII entre o primeiro caractere das duas.
notar o operador == que a comparao de igualdade. o operador = de atribuio.
Estes operadores tambm so binrios, ie, comparam dois operandos. o resultado de uma expresso relacional d um
valor bool (verdadeiro=1 ou falso=0)
4 != 4 false
4 == 5 false
Eu ainda posso comparar um int com um float que isso no d problema. ou seja com dados nmericos no h
problema. Comparaes entre dois caracteres tambm no h problema pois os caracteres so nmeros na tabela
ASCII. Mas no usem para strings (pois a estaramos a comparar o qu, se as strings so conjunto de caracteres?)
No esquecer o ponto que o digito pode ser um char ou estar em forma nmerica. e esse char vai ter o valor na
tabela. ns num capitulo posterior iremos ver que poderemos fazer a converso de char para int e vice versa.
Precedncia dos operadores relacionais
Table: Precedence of Relational Operators
Precedence Operator
Highest > >= < <=
Lowest == !=
Novamente existe a regra da esquerda para a direita caso haja igualdade de precedncia
Operadores lgicos
Estes operadores comparam j condies de precedncia Table: Logical Operators
Operator Name What It Does
&& And Connects two relational expressions. Both expressions must be true for the overall expression to be true.
|| Or Connects two relational expressions. If either expression is true, the overall expression is true.
! Not Reverses the truthof an expression, making a true expression false, and a false expression true.
Estes operadores tambm so binrios mas desta vez os operandos so resultados boolean, que podem advir dos
operadores relacionais (comparao) pois davam valores boolean.
Para o operador and (&&) basta uma das comparaes ser falsa paro resultado ser falso
Para o operador or (||) basta uma das comparaes dos operandos ser verdadeira para se tornar verdadeira
Por fim o operador not um operador unrio apenas para um valor boolean que pode ser resultado de
comparao
Exemplo:
if (age <= 12 || age >= 65)
printf("Admission is free");
else
printf("You have to pay");
Operadores
42
Precedncia Operadores lgicos e Relacionais
Tabela: A preedenia dos operadores logicos e relacionais
Operador (da mais alta para a mais baixa)
!
Relacionais (>, >=, <, <=, ==. !=)
&&
||
cuidado!
if (!age > 12 && age < 65)
Note o ! no exemplo. sempre bom recorrer aos parnteses
Operadores Lgicos Bit a Bit
Operador Aco
& AND
OR
^ XOR (OR exclusivo)
~ NOT
>> Deslocamento de bits direita
<< Deslocamento de bits esquerda
Deslocamento de bits
x = a << b igual a x = a*2^b;
x = a >> b igual a x = a/2^b;
Todos os Operadores
Comparaes de precedncia entre Operadores aritmticos, relacionais e lgicos
Level Operator Description Grouping
1 :: scope Left-to-right
2 () [] . -> ++ -- dynamic_cast static_cast reinterpret_cast const_cast typeid postfix Left-to-right
3 ++ -- ~ ! sizeof new delete unary (prefix) Right-to-left
* & indirection and reference (pointers) Right-to-left
+ - unary sign operator Right-to-left
4 (type) type casting Right-to-left
5 .* ->* pointer-to-member Left-to-right
6 * / % multiplicative Left-to-right
7 + - additive Left-to-right
8 << >> shift Left-to-right
9 < > <= >= relational Left-to-right
Operadores
43
10 == != equality Left-to-right
11 & bitwise AND Left-to-right
12 ^ bitwise XOR Left-to-right
13 | bitwise OR Left-to-right
14 && logical AND Left-to-right
15 || logical OR Left-to-right
16 ?: Description Right-to-left
17 = *= /= %= += -= >>= <<= &= ^= != assignment Right-to-left
18 , comma Left-to-right
Exerccios
(7 == 5) // evaluates to false.
(5 > 4) // evaluates to true.
(3 != 2) // evaluates to true.
(6 >= 6) // evaluates to true.
(5 < 5) // evaluates to false
(a == 5) // evaluates to false since a is not equal to 5.
(a*b >= c) // evaluates to true since (2*3 >= 6) is true.
(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is false.
((b=2) == a) // evaluates to true.
!(5 == 5) // evaluates to false because the expression at its right (5 == 5) is true.
!(6 <= 4) // evaluates to true because (6 <= 4) would be false.
!true // evaluates to false
!false // evaluates to true.
( (5 == 5) && (3 > 6) ) // evaluates to false ( true && false ).
( (5 == 5) || (3 > 6) ) // evaluates to true ( true || false ).
Controle de fluxo
44
Controle de fluxo
Controle de fluxo
Dificilmente um programa em C ir executar sempre as mesmas instrues, na mesma ordem, independentemente do
que tenha acontecido anteriormente ou do valor que foi fornecido. muito comum que algum queira que um
pedao de cdigo s seja executado se uma certa condio for verdadeira; tambm comum querer que um pedao
de cdigo seja repetido vrias vezes, de tal maneira que simplesmente copiar o cdigo no resolveria o problema ou
seria trabalhoso demais. Para casos como esses, existem as estruturas de controle de fluxo.
Em C, existem vrias instrues relacionadas ao controle de fluxo:
if, que executa um bloco apenas se uma condio for verdadeira;
switch, que executa um bloco de acordo com o valor de uma expresso ou varivel;
for, que executa um bloco repetidas vezes enquanto uma condio for verdadeira, executando uma instruo
(geralmente de incremento ou decremento de uma varivel) aps cada execuo;
while, que executa um bloco enquanto uma condio for verdadeira;
do, semelhante ao while, mas a condio avaliada aps a execuo (e no antes);
goto, que simplesmente pula para um lugar pr-definido.
Porm, antes de entrar no estudo dessas estruturas, voc deve saber como escrever uma condio. o que
explicamos a seguir.
Expresses de condio
Uma expresso de condio uma expresso normal em C que, quando avaliada, ser interpretada como verdadeira
ou falsa. Em C, na verdade, esse valor um valor inteiro que sendo 0 (zero) significa falso, sendo qualquer outro
nmero significa verdadeiro.
Geralmente em expresses condicionais usamos os operadores relacionais, ou seja, que avaliam a relao entre seus
dois operandos. Existem seis deles:
Operador Significado
> maior que
>= maior ou igual a
< menor que
<= menor ou igual a
== igual a
!= diferente de
Todos esses operadores so binrios, ou seja, trabalham com dois valores ou operandos. Esses operadores sempre
comparam o valor da esquerda com o da direita, ou seja, a expresso a > b significa "a maior que b".
Note que para saber se dois nmeros so iguais devemos usar dois sinais de igual. Um erro muito comum
esquecer de um deles, transformando a comparao numa atribuio por exemplo:
if (x = 1)
...
O que acontece aqui que a varivel x recebe o valor 1, de modo que a expresso entre parnteses tambm ter o
valor 1 tornando a condiosempre verdadeira. Similarmente, se usssemos o nmero zero, a expresso sempre
seria falsa. Portanto, sempre tome cuidado com esse tipo de comparao. A maneira certa de comparar com um
Controle de fluxo
45
nmero :
if (x == 1)
...
Tambm comum que combinemos condies. Por exemplo, podemos querer que um nmero seja menor que 10 ou
maior que 50. Como o operador "ou" "||", escreveramos: n < 10 || n > 50. A seguir voc v os
operadores lgicos:
Operador Significado
|| ou (OR)
&& e (AND)
! no (NOT)
Algumas explicaes sobre os operadores lgicos:
O operador "no" unrio, ou seja, uma operao que envolve apenas um valor. O que ele faz inverter o
valor de seu operando: retorna falso se a expresso for verdadeira e vice-versa. Deve-se usar parnteses ao negar
uma expresso: !(x > 6), por exemplo.
O operador "ou" retorna "verdadeiro" se pelo menos um dos operandos for verdadeiro; retorna "falso" apenas se
ambos forem falsos.
O operador "e" retorna "verdadeiro" apenas se ambos os seus operandos forem verdadeiros.
Observao Se voc quer saber se um nmero est entre outros dois, a sintaxe matemtica (10 < n < 50) no
funcionar. Se voc usar esse cdigo, na verdade primeiramente ser avaliada a expresso 10 < n, que poder
resultar em 0 ou 1. Portanto, a expresso equivale a (0 ou 1) < 50, o que sempre verdadeiro.
A comparao correta envolveria o operador "e" (&&): 10 < n && n < 50.
Pelo fato de todo valor diferente de zero ser avaliado como verdadeiro e zero como falso, existem as seguintes
equivalncias (apenas quando estas expresses so usadas como condies):
(x == 0) equivale a (!x)
(x != 0) equivale a (x)
Testes
Testes so estruturas de controle que executam certos blocos de cdigo apenas se uma certa condio for verdadeira.
Existem trs estruturas desse tipo em C:
if
O teste if avalia uma condio e, se ela for verdadeira, executa um bloco de cdigo. A sintaxe correspondente a isso
:
if (condio) {
... /* bloco a ser executado se a condio for verdadeira */
}
Mas tambm podemos especificar um bloco a ser executado caso a condio for falsa. Nesse caso, escrevemos:
if (condio) {
... /* bloco a ser executado se a condio for verdadeira */
}
else {
Controle de fluxo
46
... /* bloco a ser executado se a condio for falsa */
}
As chaves podem ser omitidas caso haja apenas uma instruo no bloco. Por exemplo:
if (x == 5)
printf ("x igual a 5.\n");
Perceba que, se esquecermos as chaves, o compilador no dever dar nenhum erro; no entanto, tudo que exceder a
primeira instruo ser executado incondicionalmente, mesmo que esteja na mesma linha! No exemplo a seguir, a
frase "x igual a 5" seria exibida mesmo que o nmero no fosse 5!
if (x == 5)
j++; printf ("x igual a 5.\n");
Podemos avaliar diversas condies com os testes if, bastando para isso colocar um novo teste no bloco else.
Tambm possvel aninhar blocos if, ou seja, colocar um dentro de outro:
if (x > 9) {
printf ("x maior que 9.\n");
}
else if (x >= 5) {
printf ("x maior ou igual a 5, mas no maior que 9.\n");
}
else {
if (x == 0) {
printf ("x igual a zero.\n");
}
else {
printf ("x no-nulo e menor que 5.\n");
}
}
switch
O teste switch compara uma expresso com diversos valores que podem estar associados a blocos de cdigos
diferentes, e executa o bloco de cdigo correspondente ao valor encontrado. Voc tambm pode especificar um bloco
que deve ser executado caso nenhum dos outros valores seja encontrado: o bloco default ("padro" em ingls).
switch (expresso) {
case valor1:
instrues;
break;
case valor2:
instrues;
break;
...
default:
instrues;
}
Controle de fluxo
47
Note que no teste switch no precisamos usar chaves em volta dos blocos, a menos que declaremos variveis neles.
Um exemplo da utilizao de switch seria a criao de um menu:
int opcao;
printf ("[1] Cadastrar cliente\n"
"[2] Procurar cliente\n"
"[3] Inserir pedido\n"
"[0] Sair\n\n"
"Digite sua escolha: ");
scanf ("%d", &opcao);

switch (opcao) {
case 1:
cadastra_cliente();
break;
case 2:
procura_cliente();
break;
case 3:
insere_pedido();
break;
case 0:
return 0;
default:
printf ("Opo invlida!\n");
}
A instruo break indica que deve-se continuar a execuo aps o final do bloco switch (pulando o que estiver
no meio). Se ela no fosse usada, para um certo valor encontrado, seriam executadas tambm as instrues de todos
os valores abaixo dele. Em alguns casos, podemos omitir intencionalmente a instruo break. Por exemplo, no
exemplo acima, no colocamos uma instruo break para o valor zero, pois quando retornamos de uma funo
(return 0) o bloco switch j abandonado.
Tambm podemos querer que uma instruo seja executada para mais de um valor. Vamos supor que no nosso menu
as duas primeiras opes fossem "Cadastrar pessoa fsica" e "Cadastrar pessoa jurdica", e tvessemos uma funo
que faz o cadastro diferentemente dependendo do valor da varivel pessoa_fisica. Poderamos fazer um cdigo
assim:
switch (opcao) {
case 1: /* pessoa fsica */
pessoa_fisica = 1;
case 2:
cadastra();
break;
...
}
Nesse caso, para qualquer uma das duas opes seria executada a funo cadastra, mas se selecionarmos "pessoa
fsica" a varivel ser atribuda antes.
Controle de fluxo
48
Operador ternrio "?:"
O operador ternrio ?: uma alternativa abreviada da estrutura if/else. Ele avalia uma expresso e retorna um certo
valor se ela for verdadeira, ou outro valor se ela for falsa. Sua sintaxe :
condio ? valorSeVerdadeira : valorSeFalsa
Note que, ao contrrio de if, ao usarmos o operador condicional ?: precisamos sempre prover tanto o valor para o
caso de a condio ser falsa quanto o valor para o caso de ela ser verdadeira.
O operador condicional pode ser usado em situaes como essa:
int horaAbertura = (diaSemana == DOMINGO) ? 11 : 9;
printf ("Abrimos s %d horas", horaAbertura);
Ou seja, se o dia da semana for domingo, a varivel horaAbertura ser definida para 11; caso contrrio, ser
definida para 9.
Outro exemplo:
if (numMensagens > 0) {
printf ("Voc tem %d mensage%s",
numMensagens,
(numMensagens > 1) ? "ns" : "m");
}
Neste caso, o programa utilizaria "mensagens" caso houvesse mais de uma mensagem, e "mensagem" caso houvesse
apenas uma mensagem.
Loops
Loops so conjuntos de instrues que devem ser executadas repetidas vezes, enquanto uma condio for verdadeira.
Em C h 3 tipos de loops: while, do ... while e for.
while
O loop while testa uma condio; se ela for verdadeira, o bloco correspondente executado e o teste repetido.
Se for falsa, a execuo continua logo aps o bloco. A sintaxe de while :
while (condio) {
...
}
Por exemplo:
while (a < b)
{
printf ("%d menor que %d", a, b);
a++;
}
Este cdigo seria executado at que a fosse igual a b; se a fosse igual ou maior que b, nada seria executado. Por
exemplo, para b = 10 e a < 10, a ltima mensagem que o usurio veria "9 menor que 10".
Repare que o loop while como fosse um if, ou seja, o bloco executado se a condio for verdadeira. A diferena
que ao final da execuo, o while executado novamente, mas o if no. No loop while (assim como nos loops do e
for) tambm podemos usar a sintaxe abreviada para apenas uma instruo:
Controle de fluxo
49
while (a < b)
a++;
Loops infinitos
Voc pode fazer loops infinitos com while, usando uma condio que sempre verdadeira, como "1 == 1" ou
simplesmente "1" (que, como qualquer valor no-nulo, considerado "verdadeiro"):
while (1) {
...
}
Voc pode sair de um loop infinito ou no com a instruo break, que voc j viu no teste switch e ser
explicada mais abaixo.
do ... while
O loop "do ... while" exatamente igual ao "while" exceto por um aspecto: a condio testada depois do
bloco, o que significa que o bloco executado pelo menos uma vez. A estrutura do ... while executa o bloco,
testa a condio e, se esta for verdadeira, volta para o bloco de cdigo. Sua sintaxe :
do {
...
} while (condio);
Note que, ao contrrio das outras estruturas de controle, necessrio colocar um ponto-e-vrgula aps a condio.
do
{
printf ("%d\n", a);
a++;
}
while (a < b);
Um exemplo de utilizao de do ... while em um menu. Pediramos que o usurio escolhesse uma opo at
que ele escolhesse uma opo vlida:
#include <stdio.h>

int main ()
{
int i;
do {
printf ("Escolha a fruta pelo nmero:\n\n");
printf ("\t(1) Mamo\n");
printf ("\t(2) Abacaxi\n");
printf ("\t(3) Laranja\n\n");
scanf("%d", &i);
} while (i < 1 || i > 3);

switch (i) {
case 1:
printf ("Voc escolheu mamo.\n");
Controle de fluxo
50
break;
case 2:
printf ("Voc escolheu abacaxi.\n");
break;
case 3:
printf ("Voc escolheu laranja.\n");
break;
}
return 0;
}
for
O loop for nada mais que uma abreviao do loop while, que permite que alguma inicializao seja feita antes
do loop e que um incremento (ou alguma outra ao) seja feita aps cada execuo sem incluir o cdigo dentro do
bloco. A sua forma geral
for (inicializao; condio; incremento) {
instrues;
}
E equivale a
inicializao;
while (condio) {
instrues;
incremento;
}
Um exemplo do uso de for:
for (a = 1; a < 10; a++) {
if(a == 1)
puts ("Numero de voltas previstas 9.");
printf("Numero de loop ou volta : %i ", a );
printf("Valor de a : %i ", a );
}
Nesse exemplo, primeiro definimos o valor de a como 1; depois, o cdigo (...) repetido enquanto a for menor que
dez, incrementando em uma unidade o valor de a aps cada execuo do cdigo. Analisando essas condies, voc
podera perceber que o cdigo ser executado nove vezes: na primeira execuo, temos a = 1; aps a nona
execuo, a igual a 10, e portanto o bloco no ser mais repetido.
Tambm podemos dar mais de uma instruo de inicializao ou de incremento (separadas por vrgula), alm de
poder usar naturalmente condies compostas com o uso dos operadores lgicos:
for (a = 1, b = 1; a < 10 && (b / a) < 20; a++, b *= 2) {
...
}
Nesse exemplo, "a" e "b" so inicializados com o valor 1. A cada loop, o valor de "a" incrementado em uma
unidade e o de "b" dobrado. Isso ocorre enquanto "a" for menor que 10 e a razo entre "b" e "a" for menor que 20.
Se voc construir uma tabela com os valores de cada varivel a cada loop (ou colocar algum contador dentro do
Controle de fluxo
51
loop), ver que ocorrem oito execues.
Assim como while, o loop for testa a condio; se a condio for verdadeira ele executa o bloco, faz o incremento e
volta a testar a condio. Ele repete essas operaes at que a condio seja falsa.
Podemos omitir qualquer um dos elementos do for se desejarmos. Se omitirmos a inicializao e o incremento, o
comportamento ser exatamente igual ao de while. Se omitirmos a condio, ficaremos com um loop infinito:
for (inicializao; ; incremento) {
...
}
Podemos tambm omitir o bloco de cdigo, se nos interessar apenas fazer incrementos ou se quisermos esperar por
alguma situao que estabelecida por uma funo externa; nesse caso, usamos o ponto-e-vrgula aps os parnteses
de for. Isso tambm valido para o loop while:
for (inicializao; condio; incremento) ;
while (condio) ;
Por exemplo, suponha que temos uma biblioteca grfica que tem uma funo chamada graphicsReady(), que indica
se podemos executar operaes grficas. Este cdigo executaria a funo repetidas vezes at que ela retornasse
"verdadeiro" e ento pudssemos continuar com o programa:
while (!graphicsReady()) ;
break e continue
Voc j viu break sendo usado para sair do teste switch; no entanto, ele funciona tambm nos loops while,
do e for. Nos trs casos, ele sai do ltimo loop iniciado (mesmo que haja mais de um). Por exemplo:
while (1) {
if (a > b)
break;
a++;
}
break sempre faz com que a execuo do programa continue na primeira instruo seguinte ao loop ou bloco.
A instruo continue parecida com break, porm ao execut-la saltamos para a prxima iterao loop ao invs
de termin-lo. Usar continue equivale a chegar ao final do bloco; os incrementos so realizados (se estivermos em
um loop for) e a condio reavaliada (qualquer que seja o loop atual).
#include <stdio.h>

int main()
{
int opcao = 0;
while (opcao != 5)
{
printf("Escolha uma opo entre 1 e 5: ");
scanf("%d", &opcao);

/* se a opo for invlida, volta ao incio do loop */
if (opcao > 5 || opcao < 1) continue;
switch (opcao)
Controle de fluxo
52
{
case 1:
printf("\n --> Primeira opcao..");
break;
case 2:
printf("\n --> Segunda opcao..");
break;
case 3:
printf("\n --> Terceira opcao..");
break;
case 4:
printf("\n --> Quarta opcao..");
break;
case 5:
printf("\n --> Abandonando..");
break;
}
}

return 0;
}
Esse exemplo recebe uma opo do usurio. Se ele digitar uma opo invlida (ou seja, no for um nmero de 1 a 5),
a instruo continue voltar ao comeo do loop e o programa pedir novamente a entrada do usurio. Se ele digitar
uma opo vlida, o programa seguir normalmente.
Saltos incondicionais: goto
O goto uma instruo que salta incondicionalmente para um local especfico no programa. Esse local
identificado por um rtulo. A sintaxe da instruo goto :
goto nome_do_rtulo;
Os nomes de rtulo so identificadores sufixados por dois-pontos (:), no comeo de uma linha (podendo ser
precedidos por espaos). Por exemplo:
nome_do_rtulo:
...

goto nome_do_rtulo;
Muitos programadores evitam usar o goto pois a maioria dos saltos pode ser feita de maneira mais clara com
outras estruturas da linguagem C. Na maioria das aplicaes usuais, pode-se substituir o goto por testes, loops e
chamadas de funes.
Controle de fluxo
53
Terminando o programa
O programa pode ser terminado imediatamente usando a funo exit:
void exit (int codigo_de_retorno);
Para utiliz-la deve-se colocar um include para o arquivo de cabealho stdlib.h. Esta funo aborta a execuo do
programa. Pode ser chamada de qualquer ponto no programa e faz com que o programa termine e retorne, para o
sistema operacional, o cdigo_de_retorno. A conveno mais usada que um programa retorne zero no caso de um
trmino normal e retorne um nmero no nulo no caso de ter ocorrido um problema.
#include <stdio.h>
#include <stdlib.h> /* Para a funo exit() */
int main (void)
{
FILE *fp;
...
fp=fopen ("exemplo.bin","wb");
if (!fp)
{
printf ("Erro na abertura do arquivo. Fim de programa.");
exit (1);
}
...
return 0;
}
Funes
54
Funes
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
O que funo
Uma funo um pedao de cdigo que faz alguma tarefa especfica e pode ser chamado de qualquer parte do
programa quantas vezes desejarmos.
Podemos tambm dizer que funes agrupam operaes em um s nome que pode ser chamado em qualquer parte do
programa. Essas operaes so ento executadas todas as vezes que chamamos o nome da funo.
Utilizamos funes para obter:
Clareza do cdigo: separando pedaos de cdigo da funo main(), podemos entender mais facilmente o que
cada parte do cdigo faz. Alm disso, para procurarmos por uma certa ao feita pelo programa, basta buscar a
funo correspondente. Isso torna muito mais fcil o ato de procurar por erros.
Reutilizao: muitas vezes queremos executar uma certa tarefa vrias vezes ao longo do programa. Repetir todo o
cdigo para essa operao muito trabalhoso, e torna mais difcil a manuteno do cdigo: se acharmos um erro
nesse cdigo, teremos que corrigi-lo em todas as repeties do cdigo. Chamar uma funo diversas vezes
contorna esses dois problemas.
Independncia: uma funo relativamente independente do cdigo que a chamou. Uma funo pode modificar
variveis globais ou ponteiros, mas limitando-se aos dados fornecidos pela chamada de funo.
A ideia funes permitir voc encapsular vrias operaes em um s escopo que pode ser invocado ou chamado
atravs de um nome. Assim possvel ento chamar a funo de vrias partes do seu programa simplesmente usando
o seu nome.
Exemplo:
#include <stdio.h>
int main(void) {
imprime_par(3,4);
imprime_par(-2,8);
return 0;
}
No exemplo acima, a funo imprime_par foi usada para executar o pedao de programa que imprime um par de
nmeros. A sada do programa acima ser:
{3,4}
{-2,8}
A funo imprime_par definida da seguinte forma:
void imprime_par(int a, int b)
{
printf("{ %d, %d }\n",a,b);
}
O programa completo em C mostrado abaixo:
Funes
55
#include <stdio.h>
/**
* Declarao da funo imprime_par
* Essa funo recebe dois inteiros como argumento e os imprime
* da seguinte forma {a,b}
*/
void imprime_par(int a, int b);
int main(int argc, char **argv)
{
imprime_par(3,4); //chamando a funo
imprime_par(-2,8); //chamando novamente
return 0;
}
//Implementao da funo
//A implementao da funo pode conter vrias linhas de cdigo
void imprime_par(int a, int b)
{
printf("{ %d, %d }\n",a,b);
}
A definio de funes em C devem ser feitas antes do uso das mesmas. Por isso em nosso exemplo definimos a
funo imprime_par antes de us-la dentro do main.
A linha que define ou declara a funo tambm conhecida como assinatura da funo. Normalmente as
assinaturas das funes so definidas dentro de arquivos de cabealho .h
Definindo uma funo
Uma funo pode necessitar de alguns dados para que possa realizar alguma ao baseada neles. Esses dados so
chamados parmetros da funo. Alm disso, a funo pode retornar um certo valor, que chamado valor de
retorno. Os parmetros (e seus tipos) devem ser especificados explicitamente, assim como o tipo do valor de
retorno.
A forma geral da definio de uma funo :
[tipo de retorno da funo] [nome da funo] (1 parmetro, 2
parmetro, )
{
//cdigo
}
Para o nome da funo e dos parmetros valem as mesmas regras que foram dadas para os nomes de variveis.
No podemos usar o mesmo nome para funes diferentes em um programa.
Todas as funes devem ser definidas antes da funo main, ou deve ser feito o prottipo da funo, que
veremos mais adiante.
O cdigo deve estar obrigatoriamente dentro das chaves e funciona como qualquer outro bloco.
Funes
56
Valor de retorno
Freqentemente, uma funo faz algum tipo de processamento ou clculo e precisa retornar o resultado desse
procedimento. Em C, isso se chama valor de retorno e pode ser feito com a instruo return. Para poder retornar
um valor, precisamos especificar seu tipo (char, int, float, double e variaes). Para efetivamente retornar um valor,
usamos a instruo return seguida do valor de retorno, que pode ou no vir entre parnteses. Um exemplo bem
simples de funo que retorna um valor inteiro:
int tres()
{
return 3; // poderia tambm ser return (3);
}
O tipo de retorno, alm dos tipos normais de variveis (char, int, float, double e suas variaes), pode ser o tipo
especial void, que na verdade significa que no h valor de retorno.
Nota Muitos livros dizem que a funo main tem tipo de retorno void, o que no est correto. Segundo o padro da
linguagem C, a funo main deve ter retorno do tipo int. Compiladores como o gcc daro mensagens de erro caso a
funo main() no seja definida corretamente.
Parmetros
Como j foi dito, um parmetro um valor que fornecido funo quando ela chamada. comum tambm
chamar os parmetros de argumentos, embora argumento esteja associado ao valor de um parmetro.
Os parmetros de uma funo podem ser acessados da mesma maneira que variveis locais. Eles na verdade
funcionam exatamente como variveis locais, e modificar um argumento no modifica o valor original no contexto
da chamada de funo, pois, ao dar um argumento numa chamada de funo, ele copiado como uma varivel local
da funo. A nica maneira de modificar o valor de um parmetro usar ponteiros, que sero introduzidos mais
adiante.
Para declarar a presena de parmetros, usamos uma lista de parmetros entre parnteses, com os parmetros
separados por vrgulas. Cada declarao de parmetro feita de maneira semelhante declarao de variveis: a
forma geral tipo nome. Por exemplo:
int funcao (int a, int b)
float funcao (float preco, int quantidade)
double funcao (double angulo)
Para especificar que a funo no usa nenhum parmetro, a lista de parmetros deve conter apenas a palavra-chave
void. No entanto, ela freqentemente omitida nesses casos. Portanto, voc poderia escrever qualquer uma destas
duas linhas:
void funcao (void)
void funcao ()
Note que os nomes dos parmetros so usados apenas na prpria funo (para distinguir os argumentos); eles no
tm nenhuma relao com as variveis usadas para chamar a funo.
Funes
57
Chamadas de funes
Para executar uma funo, fazemos uma chamada de funo, que uma instruo composta pelo nome da funo,
seguido pela lista de argumentos entre parnteses:
nome_da_funo (arg1, arg2, ...);
Os argumentos podem ser qualquer tipo de expresso: podem ser variveis, valores constantes, expresses
matemticas ou at mesmo outras chamadas de funo.
Lembre que voc deve sempre dar o mesmo nmero de argumentos que a funo pede. Alm disso, embora algumas
converses de tipo sejam feitas automaticamente pelo compilador, voc deve atender aos tipos de argumentos.
Note que o valor dos argumentos copiado para a funo, de maneira que as variveis originais ficam inalteradas
mesmo que na funo tentemos alter-las. A isso chamamos passagem de argumentos por valor (ao contrrio de por
referncia). Veremos como modificar as variveis originais na seo Ponteiros.
A prpria chamada de funo tambm uma expresso cujo valor o valor de retorno da funo, bastando coloc-la
no lado direito de um sinal de igual para guardar o valor numa varivel. Por exemplo, se a funo "quadrado" retorna
o quadrado de um nmero inteiro, podemos fazer assim para calcular o quadrado de 11 na varivel x:
int x = quadrado (11);
Dois exemplos
#include <stdio.h>

int quadrado (int x)
{
return (x * x);
}

void saudacao (void)
{
printf ("Ol!\n");
}

void despedida (void)
{
printf ("Fim do programa.\n");
}

int main ()
{
int numero, resultado;
saudacao ();

printf ("Digite um nmero inteiro: ");
scanf ("%d", &numero);
resultado = quadrado (numero);
printf ("O quadrado de %d %d.\n", numero, resultado);
Funes
58

despedida ();
return 0;
}
Voc veria na tela, ao executar o programa:
Ol!
Digite um nmero inteiro: 42
O quadrado de 42 1764.
Fim do programa.
Repare que, ao chegar na chamada de uma funo, o programa passa o controle para essa funo e, aps seu trmino,
devolve o controle para a instruo seguinte na funo original.
Mais um exemplo, com uma funo de 3 argumentos:
#include <stdio.h>

/* Multiplica 3 numeros */
void mult (float a, float b, float c)
{
printf ("%f",a*b*c);
}

int main ()
{
float x, y;
x = 23.5;
y = 12.9;
mult (x, y, 3.87);
return 0;
}
Prottipo ou Declarao de funo
Quando um programa C est sendo compilado e uma chamada de funo encontrada, o compilador precisa saber o
tipo de retorno e os parmetros da funo, para que ele possa manipul-los corretamente. O compilador s tem como
saber isso se a funo j tiver sido definida. Portanto, se tentarmos chamar uma funo que est definida abaixo da
linha onde estamos fazendo a chamada, ou mesmo em outro arquivo, o compilador dar uma mensagem de erro, pois
no conseguiu reconhecer a funo.
//Exemplo de erro de chamada de funo
int main()
{
int a = 1;
int b = 2;
soma(a,b); // erro: a funo est definida abaixo desta linha!
}
void soma(int a, int b)
{
Funes
59
printf("%d", a+b);
}
Nesses casos, podemos declarar uma funo antes de defini-la. Isso facilita o trabalho de usar diversas funes:
voc no precisar se importar com a ordem em que elas aparecem nos arquivos.
A declarao de funo (tambm chamada de prottipo de funo) nada mais que a definio da funo sem o
bloco de cdigo. Como uma instruo, ela deve ser seguida de um ponto-e-vrgula. Portanto, para declarar a funo:
int quadrado (int x)
{
return (x * x);
}
escreveramos:
int quadrado (int x);
Numa declarao, tambm podemos omitir os nomes dos parmetros, j que estes so ignorados por quem chama a
funo:
int quadrado (int);
Poderamos, por exemplo, reorganizar o incio do programa-exemplo dado um pouco acima, o que permitiria colocar
as funes em qualquer ordem mesmo que houvesse interdependncia entre elas:
#include <stdio.h>

int quadrado (int x);
void saudacao (void);
void despedida (void);

// seguem as funes do programa
Note que a definio da funo no deve contradizer a declarao da mesma funo. Se isso ocorrer, uma mensagem
de erro ser dada pelo compilador.
Variveis locais versus globais
Quando declaramos as variveis, ns podemos faz-lo
Dentro de uma funo
Fora de todas as funes inclusive a main().
As primeiras so as designadas como locais: s tm validade dentro do bloco no qual so declaradas. As ltimas so
as globais, elas esto vigentes em qualquer uma das funes.
Quando uma funo tem uma varivel local com o mesmo nome de uma varivel global a funo dar preferncia
varivel local. Daqui conclui-se e bem que, podemos ter variveis com o mesmo nome, o que contradiz o que ns
dissemos no capitulo das variveis.
Ento reformulamos:
Apenas na situao em que temos 2 variveis locais que colocada a restrio de termos nomes diferentes
caso contrrio no conseguiramos distinguir uma da outra.
"largo" e "alto" so variveis internas fazem parte de "minhaFuncion()".
Funes
60
/*espanhol para incultos :)*/ <== Comentrios da funo
void minhaFuncion()
{
double largo = 5;
double alto = 6;
}
As variveis largo e alto no esto definidas aqui abaixo, isto quer dizer que elas nao tem nem um valor.
E no podemos usar os valores definido dentro da "minhaFuncion", pois no h nenhuma instruo que defina que
valor usar. Lembre-se: O computador no vai adivinhar qual valor usar. Deve-se definir cada instruo.
void calcular() /*No houve definio de valor entre parenteses*/
{
long superficie = largo * alto; /*Error bip bip valor nao definido*/
return(superficie);
}
Nesse exemplo abaixo, poderemos usar o valor das variveis externas dentro de todas as funes. Exemplo:
#include <stdio.h>
/* Variaveis externas */
long largo = 10;
long alto = 20;
void F_soma ()
{
/*soma uma variavel interna
e largo e alto sao variaveis externas */
long soma = largo + alto ;
printf("largo + alto = %i \n", soma);
}
long calcular()
{
long superficie = largo * alto;
return superficie;
}
int main(void)
{
F_somma ();
printf("Superficie : %ld \n", calcular() );
return 0 ;
}
Curiosidade A palavra reservada "auto" serve para dizer que uma varivel local, mas a utilizao de auto no
mais necessria pois as variveis declaradas dentro de um bloco j so consideradas locais.
Funes
61
Passagem de parmetros por valor e por referncia
O que ns temos feito quando chamamos uma funo a dita chamada por valor. Quer dizer, quando chamamos
uma funo e passamos parmetros para a funo prottipo e depois para a funo definio, o valor dos argumentos
passados so copiados para os parmetros da funo. Estes existem independentemente das variveis que foram
passadas. Eles tomam apenas uma cpia do valor passado, e se esse valor for alterado o valor dos argumentos
passados no so alterados. Ou seja, no so alterados os valores dos parmetros fora da funo. Este tipo de
chamada de funo denominado chamada (ou passagem de parmetros) por valor.
Dito de outra maneira. Passamos a varivel a, ela entra na definio da funo como copia de ae entra como
varivel b. Se a varivel bfor alterada no decorrer da funo, o valor de ano alterado.
#include <stdio.h>
float quadrado(float num); //prottipo da funo quadrado()
int main ()
{
float num, res; //declaro 2 variveis: num , res
printf("Entre com um numero: ");
scanf("%f", &num); //associo o valor inserido varivel num
res = quadrado(num); //chamo a funo quadrado e passo o
parmetro num
printf("\n\nO numero original e: %f\n", num);
printf("e seu quadrado vale: %f\n", res);
getchar();
return 0;
}
float quadrado (float num) //descrio da funo quadrado
{
return num * num; //retorna num ao quadrado
}
Quando a funo main() executada, ela chega a meio e v uma chamada para a funo quadrado() e onde passado
o parmetro "num". Ela j estava a espera, pois "viu" o prottipo. Ela ento vai executar a funo que est depois da
funo do main(). E o que acontece que o "num", vai ficar com o dobro do valor. Esse valor do main() vai entrar
novamente no main(). E associado varivel "res". Depois temos a impresso da varivel "num" e "res". Ora o que
acontece que o valor do "num" fica igual ao valor antes de entrar na funo. Fazemos a mesma coisa agora com a
varivel "a" e "b", e vemos que agora a funo a alterada. Resumindo, o valor varivel quando entra numa outra
funo no alterado (na passagem por valor).
Quando o valor do parmetro alterado denominamos chamada (ou passagem) por referncia. O C no faz
chamadas por referncia. Mas podemos simular isto com outra arma do C que so os ponteiros, que sero melhor
explicados mais adiante.
void
Como dissemos, uma funo retorna um valor. E pode receber parmetros. O void utilizado da seguinte forma:
void funo(void)
{
//codigo
}
Funes
62
No exemplo acima, a palavra void define que:
no vai receber parmetros; e
no vai retornar qualquer valor.
Ou melhor, void uma explicitao do programador que aquela funo no vai receber ou retornar nenhum valor.
O valor da funo ignorado, mas a funo realmente retorna um valor, por isso para que o resultado no seja
interpretado como um erro e bom declarar void.
Nota
No se pode utilizar void na funo principal main, apesar de existirem exemplos com void em algumas
bibliografias. Infelizmente, alguns compiladores aceitam void main(). O main() especial e tem de retornar
um int. Uma execuo bem sucedida do programa costuma retornar 0 (zero) e, em caso de erro, retorna 1 (um).
Recursividade
Uma funo pode chamar a si prpria. Uma funo assim chamada funo recursiva. H vrias operaes
matemticas recursivas, das quais exemplos bem conhecidos so a seqncia de Fibonacci e o fatorial.
Daremos o exemplo do clculo do fatorial de um nmero, definido como o produto de todos os nmeros naturais
(no nulos) menores ou iguais a ele por exemplo, 5! (l-se "cinco fatorial") igual a .
Ateno conveno .
Uma maneira de definir o algoritmo de fatorial :
E a implementao correspondente seria esta:
#include <stdio.h>
#include <stdlib.h>
int fat(int n)
{
if (n)
return n*fat(n-1);
else return 1;
}
int main()
{
int n;
printf("\n\nDigite um valor para n: ");
scanf("%d", &n);
printf("\nO fatorial de %d e' %d", n, fat(n));
return 0;
}
Exemplo 2 :
#include <stdio.h>
#include <stdlib.h>
Funes
63
unsigned long fib(unsigned int n){
if (n == 0 || n == 1)
return n;
else
return fib(n - 1) + fib(n - 2);
}
int main(){
int n;
printf("\n\nDigite um valor para n: ");
scanf("%d", &n);
printf("\n F(%d) = %d \n ",n, fib(n));
return 0;

}
Vamos introduzir o valor 5 para este programa.
So feitas as seguintes chamadas recursivas. Observe a estrutura upside-down (rvore de cabea para baixo) criada
pelas chamadas recursivas.
Fibonacci(5)
/ \
/ \
/ \
/ \
/ \
F(4) + F(3)
/ \ / \
/ \ / \
/ \ / \
/ \ / \
/ \ / \
F(3) + F(2) F(2) + F(1)
/\ /\ | \ \
/ \ / \ | \ \
/ \ / \ | \ \
/ \ / \ | \ \
F(2) + F(1) F(1) + F(0) F(1) + F(0) 1
/\ | | | | |
/ \ | | | | |
/ \ | | | | |
/ \ | | | | |
F(1) + F(0) 1 1 0 1 0
| |
| |
| |
| |
1 0
Funes
64
Cada vez que a sub-rotina chama a si mesmo, ela deve armazenar o estado atual da sub-rotina (linha atual que est
sendo executada, os valores de todas as variveis , etc) em uma estrutura de dados chamada de "pilha".
Se voc usar a recursividade durante um longo perodo de tempo, a pilha vai ficar muito grande e o programa dar
uma mensagem de aviso.
inline
Uma funo inline, em vez de ser chamada, ser movida para o local de chamada no momento da compilao.
Se fizermos um paralelismo com as diretivas de compilao, como #define, ela vai substituir cada chamada da
funo pela prpria funo, como fosse uma macro.
Mas isto s tem vantagens para cdigos pequenos e para quem necessite muito da velocidade no processamento.
Alguns compiladores j fazem isto automaticamente.
Para tornar uma funo inline basta preceder a declarao da funo com o nome inline.
inline [tipo_de_retorno] [nome_da_funo] (argumentos)
{
//cdigo
}
Pr-processador
O pr-processador
O pr-processador C um programa que examina o programa fonte escrito em C e executa certas modificaes nele,
baseado nas diretivas de compilao (ou diretivas do pr-processador). As diretivas de compilao so comandos
que no so compilados, sendo dirigidos ao pr-processador, executado pelo compilador antes da execuo do
processo de compilao propriamente dito.
Portanto, o pr-processador modifica o programa fonte, que ainda no estaria pronto para ser entregue ao
compilador. Todas as diretivas de compilao so iniciadas pelo caractere # (sharp). As diretivas podem ser
colocadas em qualquer parte do programa, mas no podem ser colocadas na mesma linha que outra diretiva ou
instruo.
As principais diretivas de compilao so:
#include
#define
#undef
#ifdef
#ifndef
#if
#else
#elif
#endif
Pr-processador
65
Diretivas de compilao
#include
A diretiva #include diz ao pr-processador para incluir naquele ponto um arquivo especificado. Sua sintaxe :
#include "nome_do_arquivo"
ou
#include <nome_do_arquivo>
A diferena entre se usar "" e <> somente a ordem de procura nos diretrios pelo arquivo especificado. Se voc
quiser informar o nome do arquivo com o caminho completo, ou se o arquivo estiver no diretrio de trabalho, use
"arquivo". Se o arquivo estiver nos caminhos de procura pr-especificados do compilador, isto , se ele for um
arquivo do prprio sistema (como o caso de arquivos como stdio.h, string.h, etc...), use <arquivo>.
#define
A diretiva #define tem duas utilidades. Uma delas apenas definir um smbolo que pode ser testado mais tarde.
Outra definir uma constante ou ainda uma macro com parmetros. As trs maneiras de usar a diretiva so:
#define nome_do_smbolo
#define nome_da_constante valor_da_constante
#define nome_da_macro(parmetros) expresso_de_substituio
Toda vez que o pr-processador encontrar nome_da_constante no cdigo a ser compilado, ele deve substitu-lo
por valor_da_constante.
Toda vez que o pr-processador encontrar nome_da_macro(parmetros), ele deve substituir por
expresso_de_substituio, tambm substituindo os parmetros encontrados na expresso de substituio;
funciona mais ou menos como uma funo. Veja o exemplo para entender melhor.
Exemplo 1:
#include <stdio.h>
#define PI 3.1416
#define VERSAO "2.02"
int main ()
{
printf ("Programa verso %s\n", VERSAO);
printf ("O numero pi vale: %f\n", PI);
return 0;
}
Exemplo 2:
#define max(A, B) ((A > B) ? (A) : (B))
#define min(A, B) ((A < B) ? (A) : (B))
...
x = max(i, j);
y = min(t, r);
Pr-processador
66
Aqui, a linha de cdigo: x = max(i, j); ser substituda pela linha: x = ((i) > (j) ? (i) : (j));.
Ou seja, atribuiremos a x o maior valor entre i ou j.
Quando voc utiliza a diretiva #define, nunca deve haver espaos em branco no identificador (o nome da macro).
Por exemplo, a macro #define PRINT (i) printf(" %d \n", i) no funcionar corretamente porque
existe um espao em branco entre PRINT e (i).
#undef
A diretiva #undef tem a seguinte forma geral:
#undef nome_da_macro
Ela faz com que a macro que a segue seja apagada da tabela interna que guarda as macros. O compilador passa a
partir deste ponto a no conhecer mais esta macro.
#ifdef e #ifndef
O pr-processador tambm tem estruturas condicionais. No entanto, como as diretivas so processadas antes de tudo,
s podemos usar como condies expresses que envolvam constantes e smbolos do pr-processador. A estrutura
ifdef a mais simples delas:
#ifdef nome_do_smbolo
cdigo
...
#endif
O cdigo entre as duas diretivas s ser compilado se o smbolo (ou constante) nome_do_smbolo j tiver sido
definido. H tambm a estrutura ifndef, que executa o cdigo se o smbolo no tiver sido definido.
Lembre que o smbolo deve ter sido definido atravs da diretiva #define.
#if
A diretiva #if tem a seguinte forma geral:
#if expresso
cdigo
...
#endif
A sequncia de declaraes ser compilada apenas se a expresso fornecida for verdadeira. muito importante
ressaltar que a expresso fornecida no pode conter nenhuma varivel, apenas valores constantes e smbolos do
pr-processador.
#else
A diretiva #else funciona como na estrutura de bloco if (condio) {...} else {...}:
#if expresso /* ou #ifndef expresso */
cdigo /* ser executado se a expresso for verdadeira */
#else
cdigo /* ser executado se a expresso for falsa */
#endif
Um exemplo:
Pr-processador
67
#define WINDOWS
...
/* cdigo */
...
#ifdef WINDOWS
#define CABECALHO "windows_io.h"
#else
#define CABECALHO "unix_io.h"
#endif
#include CABECALHO
#elif
A diretiva #elif serve para implementar uma estrutura do tipo if (condio) {...} else if
(condio) {...}. Sua forma geral :
#if expresso_1
cdigo
#elif expresso_2
cdigo
#elif expresso_3
cdigo
.
.
.
#elif expresso_n
cdigo
#endif
Podemos tambm misturar diretivas #elif com #else; obviamente, s devemos usar uma diretiva #else e ela
deve ser a ltima (antes de #endif).
Usos comuns das diretivas
Um uso muito comum das diretivas de compilao em arquivos-cabealho, que s precisam/devem ser includos
uma vez. Muitas vezes inclumos indiretamente um arquivo vrias vezes, pois muitos cabealhos dependem de
outros cabealhos. Para evitar problemas, costuma-se envolver o arquivo inteiro com um bloco condicional que s
ser compilado se o arquivo j no tiver includo. Para isso usamos um smbolo baseado no nome do arquivo. Por
exemplo, se nosso arquivo se chama "cabecalho.h", comum usar um smbolo com o nome CABECALHO_H:
#ifndef CABECALHO_H
#define CABECALHO_H
.
.
.
#endif
Se o arquivo ainda no tiver sido includo, ao chegar na primeira linha do arquivo, o pr-processador no encontrar
o smbolo CABECALHO_H, e continuar a ler o arquivo, o que lhe far definir o smbolo. Se tentarmos incluir
novamente o arquivo, o pr-processador pular todo o contedo pois o smbolo j foi definido.
Pr-processador
68
Concatenao
O preprocessador C oferece duas possibilidades para manipular uma cadeia de caracteres .
A primeira usando o operador # que permite substituir a grafia de um parmetro .

#include<stdio.h>
int main (void)
{
/* mad equivale a "mad" */
#define String(mad) #mad
printf ( String( Estou aqui ) "\n" );
}
A segunda usando o operador ## que serve para concatenar vrios parmetros .
Ex: ban##ana igual a banana .

#include<stdio.h>
int main (void)
{
int teste = 1000 ;
#define CONCAT(x, y) x##y
/* igual a "tes" + "te" */
printf (" %i \n", CONCAT ( tes, te ) );
}
Exerccios
69
Exerccios
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
Questes
O que faz o seguinte programa?
#include <stdio.h>
int main() {
int x = 4;
scanf("%d", &x);
printf("%d", 2*x);
getchar();
}
Resoluo
Exibir o dobro do valor lido.
Escrevendo programas
Exerccio 1
Escreva uma funo que pea dois nmeros inteiros ao usurio e exibe o valor soma seguido pelo maior deles.
Resoluo
#include <stdio.h>
int main(){
int a, b, result;
printf("1");
scanf("%d", &a);
printf("2");
scanf("%d", &b);
result = a + b;
printf("A soma de %d com %d %d\n", a, b, result);
printf("O maior : %d\n", a>b? a : b );
getchar();
}
Exerccios
70
Exerccio 2
Faa um programa que converta Celsius para Fahrenheit.
#include <stdio.h>
#include <stdlib.h>
#define FERVENDO 212 /* graus Fahrenheit */
int main()
{
float var_long; double var_double; long double var_long_double;
int i;
i = 0;
printf("Fahrenheit para Celsius\n");
while(i <= FERVENDO)
{
var_long_double = 5*(i-32);
var_long_double = var_long_double/9;
var_double = var_long_double;
var_long = var_long_double;
printf("%d %f %f %lf\n", i, var_long, var_double,
var_long_double);
i = i+1;
}
return 0;
}
Exerccio 3
Faa um programa que vai lendo cada caractere que o usurio digitar. Quando o usurio digitar o caractere 'x', o
programa deve exibir todos os caracteres que foram digitados antes do 'x'.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ch;
ch = getchar();
while(ch != 'x')
{
if(ch != '\n')
{
printf("O caractere era %c, e o valor %d\n", ch, ch);
ch = getchar();
}
}
return 0;
}
Exerccios
71
Exerccio 4
Escreva um programa que comea pedindo um nmero N ao usurio e depois pede N nmeros. O programa dever
mostrar na tela todos esses nmeros ordenados do menor para o maior. Escreva sua prpria funo de ordenao.
#include <stdio.h>
#include <stdlib.h>
#define ARSIZE 10
int main(){
int m_carac[ARSIZE],qtd1;
int qtd2, pare, ultcar;
ultcar = 0;
pare = 0;
/*
* Le os caracteres para uma matriz.
* Para se for o fim da linha ou a matriz estiver cheia.
*/
while(pare != 1)
{
m_carac[ultcar] = getchar();
if(m_carac[ultcar] == '\n')
pare = 1;
else
ultcar = ultcar + 1;
if(ultcar == ARSIZE)
pare = 1;
}
ultcar = ultcar-1;
/*
* Agora executa a ordenao bolha tradicional.
*/
qtd1 = 0;
while(qtd1 < ultcar)
{
qtd2 = qtd1 + 1;
while(qtd2 <= ultcar)
{
if(m_carac[qtd1] > m_carac[qtd2])
{
/* troca */
int temp;
temp = m_carac[qtd1];
m_carac[qtd1] = m_carac[qtd2];
m_carac[qtd2] = temp;
}
qtd2 = qtd2 + 1;
}
qtd1 = qtd1 + 1;
Exerccios
72
}
qtd1 = 0;
while(qtd1 <= ultcar)
{
printf("%c\n", m_carac[qtd1]);
qtd1 = qtd1 + 1;
}
exit(EXIT_SUCCESS);
}
Exerccio 5
Faa um programa que encontra a raiz quadrada aproximada de um nmero. Para isso, use um dos mtodos
existentes.
#include <stdio.h>
#include <stdlib.h>
#define DELTA 0.0001
int main()
{
double raiz_quad(double); /* prottipo */
int i;
for(i = 1; i < 100; i++)
{
printf("Raiz de %d e' %f\n", i, raiz_quad(i));
}
return 0;
}
double raiz_quad(double x)
{ /* definio */
double aprox_atual, ult_aprox, dif;
ult_aprox = x;
dif = DELTA+1;
while(dif > DELTA)
{
aprox_atual = 0.5*(ult_aprox + x/ult_aprox);
dif = aprox_atual - ult_aprox;
if(dif < 0)
dif = -dif;
ult_aprox = aprox_atual;
}
return(aprox_atual);
}
void func_chamada(int, float);
int main()
Exerccios
73
{
func_chamada(1, 2*3.5);
exit(EXIT_SUCCESS);
}
void func_chamada(int arg_int, float arg_float)
{
float temp;
temp = arg_int * arg_float;
}
Exerccio 6
O cdigo abaixo gera nmeros primos.
#include <stdio.h>
int main()
{
int x,y, comp;
int saida = 1;
while(saida==1)
{
comp=0;
printf("Entre com o numero inteiro para o teste\n\n");
scanf("%d",&x);
for(y=1;y<=x;y++)
{
if(x%y==0)
{
comp++;
//prinf("%d",x);
}

}

if((comp>2)||(x==1))
{
printf("\n\nO numero %d, nao e primo\n",x);
}
else
{
printf("\n\nO numero %d, e primo\n",x);
}

printf("\n\nPara fazer um outra verificacao digite 1,\ncaso
contrario digite outro numero qualquer");
scanf("%d",&saida);
}
Exerccios
74

}
Cdigo mais simples e fcil de entender. Vale a pena testar!
// Por Warley V. Barbosa
#include <stdio.h>
int main()
{
int num, primo, i, res;

do
{
printf("Digite um nmero (0 para encerrar): \n");
scanf("%d", &num);

primo = 1;

for (i = 2; i < num; i++) /* repete a partir do nmero dois e vai at o nmero anterior de 'num',
incrementando varivel i a cada repetio */
{
if (num % i == 0) { // se o resto do 'num' por 'i' for zero
o nmero no primo
primo = 0;
break; // pula para a instruo seguinte
}
}

if ((primo) && (num > 1)) // 1 no primo! nem zero...
printf("O nmero %d primo! \n", num);
else
printf("O nmero %d no primo... \n", num);

}
while (num != 0); // encerra quando usurio digitar 0
}
Partindo deste cdigo, tente criar um que some o ltimo primo resultante com o anterior.
Exerccio 7
#include <stdio.h>
#include <stdlib.h>
int main()
{
int este_car, qtd_virgulas, qtd_pontos;
qtd_virgulas = qtd_pontos = 0;
Exerccios
75
este_car = getchar();
while(este_car != EOF)
{
if(este_car == '.')
qtd_pontos = qtd_pontos+1;
if(este_car == ',')
qtd_virgulas = qtd_virgulas+1;
este_car = getchar();
}
printf("%d virgulas, %d pontos\n", qtd_virgulas, qtd_pontos);

return 0;
}
Exerccio 8
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for(i = 0; i <= 10; i++)
{
switch(i)
{
case 1:
case 2:
printf("1 or 2\n");
break;
case 7:
printf("7\n");
break;
default:
printf("default\n");
}
}

int i, j;
for(i=0, j=0; i <= 10; i++, j = i*i)
{
printf("i %d j %d\n", i, j);
}
/*
* Neste exemplo, todos os valores constantes,
* exceto o ltimo, so descartados
* Note o uso dos parntesis para forar uma
* expresso vrgula em uma chamada de funo
*/
Exerccios
76
printf("Overall: %d\n", ("abc", 1.2e6, 4*3+2));

return EXIT_SUCCESS;
}
1. Repare que se no tivssemos colocado o comando break, o programa continuaria a varrer os case seguintes.
Retire este comando e use outras instrues no seu lugar
Exerccio 9
#include <stdio.h>
#include <stdlib.h>
void exibe_maior(int a1, int a2); /* declarao
*/
int main()
{
int i,j;
for(i = -10; i <= 10; i++)
{
for(j = -10; j <= 10; j++)
{
exibe_maior(i,j);
}
}
return 0;
}
/*
* Funo exibe_maior.
* Retorna: void
* Imprime na tela o maior de seus dois argumentos.
*/
void exibe_maior(int a1, int a2){ /* definio */
int maior;
if(a1 > a2)
{
maior = a1;
}
else
{
maior = a2;
}
printf("O maior entre %d e %d e' %d\n", a1, a2, maior);
}
Exerccios
77
Exerccio 10
Faa uma calculadora:
#include <stdio.h>
#include <stdlib.h>
int expr(void);
int mul_exp(void);
int unary_exp(void);
int primary(void);
int main()
{
int val;
for(;;)
{
printf("expression: ");
val = expr();
if(getchar() != '\n')
{
printf("error\n");
while(getchar() != '\n'); /* nada */
}
else
{
printf("result is %d\n", val);
}
}
return 0;
}
int expr(void)
{
int val, ch_in;
val = mul_exp();
for(;;)
{
switch(ch_in = getchar())
{
default:
ungetc(ch_in,stdin);
return(val);
case '+':
val = val + mul_exp();
break;
case '-':
val = val - mul_exp();
break;
Exerccios
78
}
}
}
int mul_exp(void)
{
int val, ch_in;
val = unary_exp();
for(;;)
{
switch(ch_in = getchar())
{
default:
ungetc(ch_in, stdin);
return(val);
case '*':
val = val * unary_exp();
break;
case '/':
val = val / unary_exp();
break;
case '%':
val = val % unary_exp();
break;
}
}
}
int unary_exp(void)
{
int val, ch_in;
switch(ch_in = getchar())
{
default:
ungetc(ch_in, stdin);
val = primary();
break;
case '+':
val = unary_exp();
break;
case '-':
val = -unary_exp();
break;
}
return(val);
}

Exerccios
79
int primary(void)
{
int val, ch_in;
ch_in = getchar();
if(ch_in >= '0' && ch_in <= '9')
{
val = ch_in - '0';
goto out;
}
if(ch_in == '(')
{
val = expr();
getchar(); /* skip closing ')' */
goto out;
}
printf("error: primary read %d\n", ch_in);
exit(EXIT_FAILURE);
out: return(val);
}
Exerccio 11
Esse programa converte um inteiro em bytes e depois realiza a operao inversa.
Faa um programa que converte um short em bytes.
#include <stdio.h>
int main (void)
{
unsigned char bytes[4]; /* Aqui o ndice indica o nmero de elementos
*/
unsigned long n = 123000;
bytes[0] = (n >> 24) & 0xFF;
bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF;
bytes[3] = n & 0xFF;
int i;

char b[500];

sprintf(b,"0 = %d, 1 = %d, 2 = %d, 3 =
%d",bytes[0],bytes[1],bytes[2],bytes[3]);

int inteiro = (bytes[0]<<24)+(bytes[1] << 16)+(bytes[2] << 8)+bytes[3];
printf("bytes %s\n",b);
printf("int = %i\n",inteiro);

Exerccios
80
getchar();
}
Vetores
Vetores
Vetores, tambm chamados arrays (do ingls) ou arranjo ou ainda matrizes, so uma maneira de armazenar vrios
dados num mesmo nome de varivel atravs do uso de ndices numricos. Em C, vetores devem sempre conter dados
do mesmo tipo de varivel.
Declaramos vetores de maneira muito semelhante declarao de variveis normais. A nica diferena que depois
do nome da varivel deve ser informada a quantidade de elementos do vetor. Para declarar um vetor chamado
vetor, com cinco elementos inteiros, escrevemos:
int vetor[5];
Note que a quantidade de elementos de um vetor no pode ser alterada depois que o vetor for declarado. Para criar
vetores de tamanho dinmico, podemos usar ponteiros, que sero abordados mais adiante.
Da mesma maneira que podemos inicializar uma varivel junto com sua declarao, podemos usar as chaves ({})
para inicializar um array.
int vetor[5] = {17, 42, 9, 33, 12};
Para fazer referncia a um valor de um elemento contido em um vetor, usamos a notao vetor[ndice], que
serve tanto para obter quanto para definir o valor de um elemento especfico, dada sua posio. Note que os
elementos so numerados a comear do zero, e, portanto, se o nmero de elementos , o ndice ou posio do
ltimo elemento ser .
vetor[0] = 3;
int x = vetor[2];
int y = vetor[5]; // ERRO!
Repare em que a ltima linha contm um erro: ela referencia um elemento do vetor que no existe. No entanto, o
compilador no se recusar a compilar esse cdigo; dar apenas um aviso. Se essa linha for executada, a varivel y
receber um valor que no tem nada a ver com o vetor.
Abreviando as declaraes
Ao inicializar um vetor com vrios valores, pode ser trabalhoso contar todos os valores para colocar o tamanho do
vetor na declarao. Por isso, em C podemos omitir o nmero de elementos quando os valores so inicializados; o
tamanho do vetor ser o nmero de valores inicializados. Por exemplo, as duas notaes abaixo so equivalentes:
int valores[5] = {1, 2, 3, 4, 5};
int valores[] = {1, 2, 3, 4, 5};
Vetores
81
Exemplo de Aplicao de Vetores
O cdigo abaixo de um programa que recebe 5 nmeros inteiros e informa qual destes maior.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

int main(void)
{
int vetor[5];
int x, i;

printf ("digite 5 numeros\n");

for (i = 0; i < 5; i++) /*Este laco faz o scan de cada elemento do vetor*/
{
scanf("%d", &vetor[i] );
}
i = 1;
x = vetor[0];

while (i < 5) /*Este laco compara cada elemento do vetor*/
{
if (vetor[i] > x)
{
x = vetor[i];
}
i++;
}

printf("\n O maior numero que voce digitou foi %d .\n",x);
getch ();
return 0;
}
Vetores multidimensionais (matrizes)
Podemos declarar ainda mais variveis
tipo_da_varivel nome_da_varivel [altura][largura];
Ateno que:
ndice mais direita varia mais rapidamente que o ndice esquerda.
No esquecer os ndices variam de zero ao valor declarado menos um.
Podemos ter ainda conjunto de variveis multidimensionais.
tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN];
onde a iniciao :
Vetores
82
tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN] = {lista_de_valores};
float vect [6] = { 1.3, 4.5, 2.7, 4.1, 0.0, 100.1 };
int matrx [3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
char str [10] = { 'J', 'o', 'a', 'o', '\0' };
char str [10] = "Joao";
char str_vect [3][10] = { "Joao", "Maria", "Jose" };
Podemos, em alguns casos, inicializar matrizes das quais no sabemos o tamanho a priori. O compilador C vai, neste
caso verificar o tamanho do que voc declarou e considerar como sendo o tamanho da matriz. Isto ocorre na hora da
compilao e no poder mais ser mudado durante o programa
Argumentos na funo main
Na seo Funes, dissemos que a funo main() aceita dois argumentos, mas no falamos mais pois um deles
envolve o conceito de vetores. Agora iremos falar mais sobre eles.
Os dois argumentos de main() indicam os argumentos dados para o programa na linha de comando, na forma de um
vetor de strings.
Exemplo de uso de parmetros na funo main
// somaComArgcArgv.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int result;
if ( argc != 3 )
{
printf("Digite soma <valor1> <valor2>\n");
return 0;
} // fim if ( argc != 3 )
result = atoi(argv[1]) + atoi(argv[2]);
printf("\nO resultado da soma de %s e %s eh: %d\n", argv[1], argv[2],
result);
}
Strings
83
Strings
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.
Strings
Strings (Ingls) so cadeias ou seqncias ordenadas de caracteres. Na verdade j trabalhamos com strings neste
livro, mas preferimos deixar maiores explicaes para um momento em que j tivesse sido introduzido o conceito de
vetor.
A linguagem C, ao contrrio de outras linguagens de programao, no possui um tipo de dados correspondente s
strings; no lugar, usam-se vetores (e ponteiros, como veremos mais adiante). Em C, strings so vetores de caracteres
terminados pelo caractere nulo ('\0'). Por exemplo:
char nome[] = {'P', 'e', 'd', 'r', 'o', '\0'};
No entanto, escrever strings dessa maneira muito trabalhoso; por isso, foi criada uma notao abreviada que
equivale notao acima e elimina a necessidade de colocar o caractere terminador:
char nome[] = "Pedro";
Assim como nos vetores, podemos acessar e modificar elementos individuais de uma string. Podemos tambm
diminuir o tamanho de uma string: uma vez que a nica marcao do tamanho o terminador \0, colocar um
terminador em outro local determinar o novo final da string. No entanto, aumentar o tamanho da string mais
difcil; isso ficar para outra seo.
Ateno ao usar-se acentos numa string. Como existem diferentes formas de codificar caracteres acentuados, o
tratamento de uma string do tipo:
char nome[] = "Joo";
pode ser diferente de uma mquina para outra. Neste captulo no sero tratados acentos, este assunto ser abordado
mais adiante.
Funes da biblioteca padro
A biblioteca padro fornece vrias funes teis para manipular strings. A seguir mostraremos algumas delas. Para
us-las, voc deve incluir o cabealho string.h no incio dos seus arquivos.
strlen
strlen retorna o tamanho, em caracteres, de uma string dada. Na verdade o strlen() procura o terminador de string
e calcula a distncia dele ao incio da string. Por exemplo:
char nome[15] = "Maria da Silva";
int s = strlen (nome);
// s conter o valor 14
/*TL'*/
Strings
84
strcpy
strcpy copia o contedo de uma string para outra e coloca um terminador de string. Sua sintaxe strcpy
(destino, origem).
char nome[] = "Clarice Lispector";
char nome2[] = "Oswald de Andrade";
strcpy (nome, nome2);
// agora nome conter "Oswald de Andrade"
Tome cuidado com strcpy(), pois se a string a ser copiada for maior que a string de destino, provavelmente voc
gravar dados em lugares indesejados um problema conhecido como estouro de buffer. Para evitar esse
problema, use a funo strncpy, que recebe um terceiro argumento que corresponde ao nmero mximo de
caracteres a serem copiados:
char msg[] = "Bom dia!";
char nome[] = "Maria da Silva";
strncpy (msg, nome, strlen(msg));
// agora msg conter "Maria da"
strcat
strcat concatena duas strings, adicionando o contedo da segunda ao final da primeira, alm do terminador (\0).
Note que a primeira string deve ter espao suficiente para conter a segunda, para que no ocorra um "estouro de
buffer". Por exemplo:
char nome[50] = "Maria";
char sobrenome[] = " da Silva";
strcat (nome, sobrenome);
// agora nome contm "Maria da Silva"
Analogamente funo strncpy, existe tambm a funo strncat, onde o nmero mximo de caracteres a
serem copiados o terceiro argumento.
strcmp
Se voc tentar criar duas strings com o mesmo contedo e compar-las como faria como nmeros, ver que elas "no
so iguais". Isso ocorre porque, na verdade, o que est sendo comparado so os endereos de memria onde esto
guardadas as strings. Para comparar o contedo de duas strings, voc deve usar a funo strcmp (ou suas
variantes):
int strcmp (char *s1, char *s2);
O valor de retorno :
menor que zero se s1 for menor que s2;
igual a zero se s1 e s2 so iguais;
maior que zero se s1 for maior que s2.
Costuma parecer estranho dizer que uma string menor ou maior que outra; na verdade essa comparao entre a
primeira letra que difere nas duas strings. Assim, se tivermos s1 = "abc" e s2 = "abd", diremos que s2
maior que s1, pois na primeira posio em que as duas strings diferem, a letra em s2 "maior".
importante notar que a comparao feita por strcmp distingue maisculas de minsculas. Isto , as strings
"ABC" e "abc" no so iguais para essa funo.
Strings
85
As variantes mais usadas de strcmp so:
strncmp - compara apenas os n primeiros caracteres das duas strings, sendo n um terceiro argumento.
stricmp - compara duas strings sem distino entre maisculas e minsculas. A sintaxe igual de strcmp.
Essa funo no faz parte da biblioteca padro, mas comumente encontrada como extenso particular de vrias
delas.
strrchr
strrchr Retorna um ponteiro sobre a ultima ocorrncia de c de uma string apontada por s se no retorna NULL .
Sua sintaxe strrchr(const char *s, int c);.
Exemplo:
char path[50] = "/teste/string";
char *p = strrchr(path, '/');
*p++;
printf("Resultado: %s \n", p );
memcpy
Sintaxe:

#include <string.h>
void *memcpy (void *dest, const void *srce, size_t n);
Descrio: Copiar um bloco de n octetos de srce para dest.
Ateno:Se as regies de srce e dest se sobreporem o comportamento da funo imprevisvel.
Valor de retorno : memcpy retorna o valor de dest .
Ex:
#include <stdio.h>
#include <string.h>
int main() {
int tab[2][5] = { { 1, 2, 3, 4, 5,
{11, 12, 13, 14, 15} };
int temp[2][5];
memcpy(temp, tab, sizeof(tab));
puts("Resultado:\n");
printf("temp[1][4] = %d\n", temp[1][4]);
return 0;
}
Strings
86
memset
Sintaxe:

#include <string.h>
void *memset (void *buffer, int c, size_t n);
Descrio: memset inicializa n octetos do buffer com o inteiro c.
Valor de retorno : O valor do buffer.
Ex:
#include <stdio.h>
#include <string.h>
int main() {
char buf[] = "W.I.K.I.";
printf("Buf antes 'memset': %s\n", buf);
memset(buf, '*', strlen(buf));
printf("Buf depois 'memset': %s\n", buf);
return 0;
}
sprintf
Descrio: A diferena entre printf e sprintf e que printf retorna o resultado para a sada padro (tela), enquanto
sprintf retorna o resultado em uma varivel. Isto muito conveniente, porque voc pode simplesmente digitar a frase
que voc quer ter e sprintf lida com a prpria converso e coloca o resultado na string que voc deseja.
Sintaxe:

#include <stdio.h>
int sprintf(char *s, const char *formato, ...);
Ex:
#include <stdio.h>
#include <string.h>

int main() {
char var[256];
char sobrenome[] = "Simpson";
char nome[] = "Homer";

int idade = 30;

sprintf(var, "%s %s tem %d anos",sobrenome, nome, idade);

Strings
87
printf ("Resultado : %s\n", var);

return 0;
}
Passagem de parmetros
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Passagem de Parmetros
Esta explicao para quem compila com o GNU gcc.
O que so parmetros?
Com os programas em interface grfica usa-se botes ou cones.
Quando utiliza-se os parmetros com o console ou prompt os parmetros so reconhecidos como opes.
Para quem usa sistemas do tipo Unix como o Linux, onde o console no banalizado como em outros SO's, mais
fcil de se entender.
Imagine que exista um programa cujo nome "Calcular" e que ele serve para executar operaes aritmticas.
Pense agora na sua execuo no shell.
$./Calcular restar
"Calcular" o nome, a "chamada" ao seu programa, enquanto que "restar" um parmetro, uma opo.
Esse programa pode comportar vrios parmetros como somar, subtrair e multiplicar, por exemplo.
Exemplo:
/*----------------------------Parmetros.c------------------------------*/
#include <stdio.h>
/* igual a int main(int argc, char *argv[]) */
int main(int argument_count, char *argument_value[])
{
int i;
printf("Nome do Programa :%s\n", argument_value[0] );
for (i = 1 ; i < argument_count; i++)
printf("Parmetros passados %d : %s\n", i, argument_value[i]);
/* De um enter no fim*/
}
Para compilar:
user@SO:/meu_diretotio$ gcc Parametros.c -o Argumentos
Como diramos s passar alguns argumentos para o compilador ;)
Examinando o cdigo
Vamos dar uma olhada na funo main(int argc, char *argv[]) vocs podem remarcar os nomes:
argc "argument count" : Conta o numero de argumentos incluindo o nome do programa.
Passagem de parmetros
88
E argv "arguments values" : Vamos dizer que cada argv[] um nome de parmetro.
Ento temos um que nos da a quantidade de parmetros e outro que nos da os nomes de cada parmetro ou opo.
So nomes tradicionais eles podem ser modificado para outros nomes desde que os tipos continuem sendo os
mesmos.
Exe:
NOME opao1 opao2 opao3 : argc = 4
$./Calcular somar depois restar : argv[] vai de argv[0] a argv[3]
Aqui argc igual a 4.
argv[] na realidade uma tabela de ponteiros exe:
argv[0] e igual a '.' '/' 'C' 'a' 'l' 'c' 'u' 'l ' 'a' 'r' '/0' Calcular
argv[1] e igual a 's' 'o' 'm' 'a' 'r' '/0' somar
Tipos de dados definidos pelo usurio
Tipos de dados definidos pelo usurio
Muitas vezes necessrio manipular dados complexos que seriam difceis de representar usando apenas os tipos
primitivos (char, int, double, float). Para isso, h, em C, trs tipos de dados que podem ser definidos pelo usurio:
estruturas (struct);
unies (union);
enumeraes (enum).
As estruturas e unies so compostas por vrias variveis (escolhidas pelo programador), por isso so ditos definidos
pelo usurio. J as enumeraes so, resumidamente, tipos cujos valores devem pertencer a um conjunto definido
pelo programador.
Estruturas
Foi proposta a fuso deste mdulo com: Programar_em_C/Estruturas (discuta).
Uma estrutura (ou struct) um tipo de dados resultante do agrupamento de vrias variveis nomeadas, no
necessariamente similares, numa s; essas variveis so chamadas membros da estrutura. Para declarar uma
estrutura, usamos a palavra-chave struct, seguida do nome que se deseja dar estrutura (ao tipo de dados) e de
um bloco contendo as declaraes dos membros. Veja um exemplo:
struct mystruct
{
int a, b, c;
double d, e, f;
char string[25];
};
Este exemplo cria um tipo de dados denominado mystruct, contendo sete membros (a, b, c, d, e, f, string). Note que o
nome mystruct o nome do tipo de dados, no de uma varivel desse tipo.
Um exemplo simples de aplicao de estruturas seria uma ficha pessoal que tenha nome, telefone e endereo; a ficha
seria uma estrutura.
Tipos de dados definidos pelo usurio
89
Ou, mais amplamente, uma estrutura seria uma representao de qualquer tipo de dado definido por mais de uma
varivel. Por exemplo, o tipo FILE* na verdade um ponteiro para uma estrutura que contm alguns dados que o
sistema usa para controlar o acesso ao fluxo/arquivo. No necessrio, para a maioria dos programadores, conhecer
a estrutura do tipo FILE.
Definindo o tipo
A definio de um tipo de estrutura feita com a palavra-chave struct, seguida do nome a ser dado ao tipo e de
um bloco contendo as declaraes dos elementos da estrutura:
struct nome_do_tipo
{
tipo_elem a;
tipo_elem b, c;
...
};
muito importante incluir o ponto-e-vrgula ao final do bloco!
Declarando
Para declarar uma varivel de um tipo j definido, fornecemos o nome do tipo, incluindo a palavra-chave struct:
struct nome_do_tipo variavel;
Tambm possvel condensar a definio do tipo e a declarao em um passo, substituindo o nome do tipo pela
definio, sem o ponto-e-vrgula:
struct mystruct
{
int a, b, c;
double d, e, f;
char string[25];
} variavel;
Tambm possvel inicializar uma estrutura usando as chaves {} para envolver os elementos da estrutura,
separados por vrgulas. Os elementos devem estar na ordem em que foram declarados, mas no obrigatrio
inicializar todos; no entanto, para inicializar um elemento, todos os anteriores devem ser inicializados tambm. Por
exemplo, poderamos declarar valores iniciais para a varivel acima da seguinte maneira:
struct mystruct variavel = {4, 6, 5, 3.14, 2.718, 0.95, "Teste"};
struct mystruct v2 = {9, 5, 7};
Tipos de dados definidos pelo usurio
90
Inicializador designado
Para quem usa o C99 com o compilador GNU. Durante a inicializao de um estrutura possvel especificar o nome
do campo com '.nome_do_campo =' antes do valor.
Exemplo:
struct mystruct v2 = {.a=9,.b=5,.c=7};
Acessando
Para acessar e modificar os membros de uma estrutura, usamos o operador de seleo. (ponto). esquerda do
ponto deve estar o nome da varivel (estrutura) e direita, o nome do membro. Podemos usar os membros como
variveis normais, inclusive passando-os para funes como argumentos:
variavel.a = 5;
variavel.f = 6.17;
strcpy (variavel.string, "Bom dia");
printf ("%d %f %s\n", variavel.a, variavel.f, variavel.string);
Vetores de estruturas
Sendo as estruturas como qualquer outro tipo de dados, podemos criar vetores de estruturas. Por exemplo, suponha
algum programa que funcione como um servidor e permita at 10 usurios conectados simultaneamente. Poderamos
guardar as informaes desses usurios num vetor de 10 estruturas:
struct info_usuario {
int id;
char nome[20];
long endereco_ip;
time_t hora_conexao;
};
struct info_usuario usuarios[10];
E, por exemplo, para obter o horrio em que o 2 usurio usurio se conectou, poderamos escrever
usuarios[1].hora_conexao.
Atribuio e cpia
Podemos facilmente copiar todos os campos de uma estrutura para outra, fazendo uma atribuio simples como a de
inteiros:
struct ponto {
int x;
int y;
};
...
struct ponto a = {2, 3};
struct ponto b = {5, 8};
b = a;
// agora o ponto b tambm tem coordenadas (2, 3)
Tipos de dados definidos pelo usurio
91
No entanto, devemos ter cuidado se a estrutura contiver campos ponteiros, pois, nesses casos, o que ser copiado o
endereo de memria (e no o contedo daquele endereo). Por exemplo, se tivermos uma estrutura que comporta
um inteiro e uma string, uma cpia sua conter o mesmo inteiro e um ponteiro para a mesma string, o que
significa que alteraes na string da cpia sero refletidas tambm no original!
Passando para funes
J vimos acima que podemos normalmente passar membros de uma estrutura como argumentos de funes. Tambm
possvel passar estruturas inteiras como argumentos:
#include <stdio.h>
struct ponto {
int x;
int y;
};
void imprime_ponto (struct ponto p)
{
printf ("(%d, %d)\n", p.x, p.y);
}
int main ()
{
struct ponto a = {3, 7};
imprime_ponto (a);
return 0;
}
No entanto, h dois possveis problemas nisso:
Alteraes nos membros da estrutura s tero efeito dentro da funo chamada, mas no na funo que a chamou.
Isso ocorre pois a estrutura passada por valor (e no por referncia).
Quando a estrutura contiver muitos elementos, a passagem por valor tornar-se- um processo de cpia de muitos
dados. Por isso, de costume passar estruturas por referncia (como ponteiros), mesmo que a estrutura em
questo seja pequena.
Unies
Foi proposta a fuso deste mdulo com: Programar em C/Unio (discuta).
Unies so parecidas com estruturas, mas h uma diferena fundamental: nas unies, todos os elementos ocupam o
mesmo espao de memria. Por isso, s possvel acessar um elemento por vez, j que uma mudana em um
elemento causar mudana em todos os outros. A definio e a declarao de unies igual das estruturas,
trocando a palavra struct por union.
H principalmente dois usos para as unies:
economia de espao, j que guardam-se vrias variveis no mesmo espao;
representao de uma informao de mais de uma maneira. Um exemplo disso so os endereos IP, que na
biblioteca de sockets podem ser representados como um grupo de 4 octetos (char) ou como um nico valor
inteiro (int). Isso feito com uma unio parecida com esta:
Tipos de dados definidos pelo usurio
92
union ip_address {
int s_long;
char s_byte[4];
};
Dessa maneira, o endereo pode ser facilmente representado de maneira humanamente legvel (com 4 octetos),
sem dificultar o processamento interno (com o valor inteiro).
Enumeraes
Foi proposta a fuso deste mdulo com: Programar em C/Enumerao (discuta).
Enumerao (enum) ou tipo enumerado um tipo de dados que tem como conjunto de valores possveis um
conjunto finito de identificadores (nomes) determinados pelo programador. Em C, cada identificador em uma
enumerao corresponde a um inteiro.
Enumeraes so definidas de maneira similar s estruturas e unies, com algumas diferenas. A palavra chave
usada enum.
enum nome_enumerao {
IDENTIFICADOR_1,
IDENTIFICADOR_2,
...
IDENTIFICADOR_n
};
Note as diferenas: no h ponto-e-vrgula no final ou no meio das declaraes (mas ainda h no final do bloco), e
no h declarao de tipos.
Com essa declarao, ao IDENTIFICADOR_1 ser atribuido o valor 0, ao IDENTIFICADOR_2 ser atribudo o
valor 1, e assim por diante. Podemos tambm explicitar os valores que quisermos colocando um sinal de igual e o
valor desejado aps o identificador.
Caso no haja valor determinado para o primeiro identificador, ele ser zero. Para os demais identificadores, o
padro seguir a ordem dos nmeros, a partir do valor do identificador anterior.
Podemos misturar identificadores de valor determinado com identificadores de valor implcito, bastando seguir a
regra acima.
Por exemplo:
enum cores {
VERMELHO, /* 0 */
AZUL = 5, /* 5 */
VERDE, /* 6 */
AMARELO, /* 7 */
MARROM = 10 /* 10 */
};
Tipos de dados definidos pelo usurio
93
Uso
Da mesma maneira que criamos uma varivel de um tipo struct ou union, podemos criar variveis de um tipo
enumerado (enum):
enum cores cor_fundo;
Para atribuir valores a uma varivel enumerada, podemos usar como valor tanto o identificador quanto o valor
correspondente. Seriam equivalentes, portanto:
cor_fundo = VERDE;
cor_fundo = 6;
Na verdade, variveis enumeradas agem de maneira quase igual aos inteiros; possvel, assim, atribuir valores que
no correspondem a nenhum dos identificadores.
Campo de bits
Na linguagem c o campo de bits (bitfields) uma estrutura um pouco estranha , em vez de usar variveis com tipos
diferentes os campos so formados com as partes de um inteiro. O tamanho de um campo de bits no pode ser maior
que o tipo usado , aqui um short .
typedef struct
{
unsigned short
campo_1: 6, /* Tamanho 6 bit */
campo_2: 6,
campo_3: 1,
campo_4: 1,
campo_5: 2;
}BIT_FIELD_1;
Essa estrutura esta formada por um tipo que tem o tamanho de um short esse mesmo tipo ser divido em pores
menores. No exemplo acima os campos tem os tamanhos 6,6,1,1,2 igual a 16 bits que o tamanho de um unsigned
short . Para acessar os campos usamos o mesmo mtodo que usamos com estruturas normais .
BIT_FIELD_1 meu_campo;
meu_campo.campo_1 = 16;
meu_campo.campo_4 = 0;
Enumerao
94
Enumerao
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Enumerations (enum)
Aqui vamos retornar a um tpico antigo.
Enumerations so um outro mtodo de definir constantes. Recordam-se? Tnhamos o:
1. 1. #define
2. 2. const int a = 1;
3. 3. enumerations.
Criando um novo tipo de dados
As enumerations definem um nova tipo de varivel e limita desde logo os valores.
enum colors {black, blue, green, cyan, red, purple, yellow, white};
A maneira mais simples de interpretar uma enumeration imagina-la como uma matriz de apenas uma linha. Temos
o nome da linha de temos as vrias clulas na linha. Cada constante enumerada (muitas vezes chamado de
enumerator) tem um valor inteiro (caso no seja especificado ele comea em zero)
Exemplo:
black blue green cyan purple yellow white
0 1 2 3 4 5 6
Mas podemos definir o valor tipo
enum forma {quadrado=5, rectangulo,triangulo=27, circulo, elipse}
ficaramos com a nossa linha do tipo:
Quadrado Rectngulo Triangulo Circulo Elipse
5 6 27 28 29
reparem nos valores dos nmeros.
A vantagem em termos enumeraes que se uma varivel declarada tipo enumerao, tem um tipo nico e os seus
valores esto limitados e podero ser verificados durante a compilao.
tal como as estruturas criar tipos de variveis.
#include <stdio.h>
/*Definindo o cabealho*/
enum cores
{
AZUL = 1,
VERDE,
BRANCO,
}; /*Aqui um ponto virgula*/
Enumerao
95
/*typedef transformamos 2 palavras em uma -> tipo_cores*/
typedef enum cores tipo_cores ;
/*A funo default da lib ou glibc*/
int main(void)
{
/*Agora usando o nosso novo tipo
* Aqui sem typedef teramos que colocar enum cores */
tipo_cores cor = VERDE ;

if(cor == 1)
{
printf("Cor azul \n");
}
if(cor == 2)
{
printf("Cor verde \n");
}
/* printf no ser executado */
if(cor == 3 )
{
printf("Cor branco \n");
}
return 0 ;
/*De um enter depois de } para evitar warning */
}
Aqui podemos ver um exemplo com uma funo "mostrarRes()" e um switch:
Em este exemplo uma constante e definida e o valor das outra ser definido automaticamente.
#include <stdio.h>
#include <stdlib.h>
void mostrarRes(int quem);
/*Aqui os valores Italia = 4 e Brasil = 5 so incrementados
automaticamente*/
enum { ARGENTINA = 3, ITALIA, BRASIL };

int main(void)
{

/*Colocamos 5 se voc for Argentino coloque 3 */
int n = BRASIL ;
Enumerao
96
mostrarRes(n);

}
void mostrarRes(int quem)
{

switch(quem)
{
case BRASIL : printf( "Brasil invencvel como de costume\n"
);
break;
case ARGENTINA : printf("Argentina um dia quem sabe\n")
;
break;
case ITALIA : printf("Foi sorte\n")
;
break;
default : printf("Se estou vivo teve erro do sistema xx \n")
;

}
printf("The end , hasta la vista\n \n");
/*De um enter depois de } para evitar warning */
}
Unio
97
Unio
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Unions
As unions so muito parecidas com as estruturas, estas guardam variveis de vrios tipos, e portanto guardam cada
varivel de acordo com a seu tipo, ie, se tivermos uma varivel membro que um int e outro float, ela guarda
exatamente de acordo com esse tipo.
O que se passa aqui que vai guardar as variveis todas com um nico tipo, que aquele que ocupa mais espao
dentro dos tipos das variveis membro, ou seja, se tivermos uma varivel membro int e outra float , a union vai
guardar estas variveis como fossem as duas float.
Declarao
union mytypes_t
{
int i;
float f;
} mytypes;
Unions com estruturas
Neste exemplo temos unions e estruturas misturados.
union mix_t
{
long l;
struct
{
short hi;
short lo;
} s;
char c[4];
} mix;
mytypes_t long l Struct Char C[4]
mix
Repare que a estrutura no tem nome
Unio
98
Anonymous unions estruturas com unions
// estrutura usando "regular union"
struct {
char title[50];
char author[50];
union {
float dollars;
int yens;
} price;
} book;
// estrutura usando "anonymous union"
struct {
char title[50];
char author[50];
union {
float dollars;
int yens;
};
} book;
Se declararmos uma unio sem nome, ela vai ficar annima e poderemos acessar seus membros diretamente atravs
dos nomes dos membros.
// Uso regular
book.price.dollars
book.price.yens
// Uso anonimo
book.dollars
book.yens
Estruturas
99
Estruturas
Esta pgina precisa ser reciclada (discuta).
Ao melhor-la, voc estar ajudando o Wikilivros.
Structures
As stuctures permitem com que possamos ter variveis de vrios tipos aglomerados sob o mesmo nome. E esse
mesmo nome vai passar a ser um novo tipo de dados tal como o int ou float.
Mas o uso disto que podemos ter valores que tenham alguma relao lgica, por exemplo guardar um int de idade e
um string de nome. Isto pode ser atributos de uma pessoa. Ou seja podemos empacotar vrias variveis de vrios
tipos com o objetivo de representar o mundo real e dar um nome a essas variveis todas.
Ao fazer isto crimos um tipo de dados da mesma forma como fazemos em relao ao int ou ao float.
Declarar uma estrutura
A sintaxe :
struct <identificador> {
<tipo> campo_um ;
<tipo> campo_dois ;
};
Aqui o tipo struct indica que vamos criar uma estrutura. O nome ou identificador pode ser alunos, famlia, etc . (tm
de ser vlidos identifiers) No esquecer o ponto e vrgula ;no fim da declarao. Campo_um e Campo_dois so
variveis membro member variables ou campo da estrutura.
Assim criamos novos tipos de dados.
Primeiro mtodo:
struct minha_estrutura
{
int variavel_um;
int campo_dois;
char fruta[40];
} ;
Aqui o identificador do tipo "struct" "minha_estrutura" dentro dessa estrutura temos trs campos o ultimo "fruta"
Agora podemos usar esse tipo "struct" para definir variveis.
struct minha_estrutura nova_estructura;
Para ter acesso aos membros definidos dentro da estrutura utilizamos um operador de seleao de membro "."(um
ponto).
nova_estrutura.fruta[0];
Nos d o primeiro caracter da palavra contida dentro do membro "fruta".
Para inicializar um campo da estrutura o processo o mesmo que usamos com as variveis.
nova_estrutura.campo_dois = 100;
Estruturas
100
Matrizes de estruturas
Uma estrutura como qualquer outro tipo de dado no C. Podemos, portanto, criar matrizes de estruturas. Vamos ver
como ficaria a declarao de um vetor de 100 fichas pessoais:
struct minha_estrutura fichas [100];
Poderamos ento acessar um campo dando um ndice do vetor fichas:
fichas[12].variavel_um;
Declarar instncias (objetos) da estrutura
Podemos declarar os objetos de duas formas:
Ao mesmo tempo que declaramos a estrutura
struct product {
int weight;
float price;
} apple, banana, melon;
Ou como uma varivel normal
struct product
{
..
}
int main()
{
struct product apple, banana, melon;
}
E at podemos declarar um array delas
Person p[20];
Pergunta: como que feito exatamente os objetos?
Para cada objeto vo ser feito uma cpia dos elementos da estrutura.
Agora isso significa que os objetos so distintos entre si em termos de reserva de memria? ie, medida que
enumero os objetos vo ser reservado para cada objeto o tamanho x de bytes? ou somam-se todos os objetos e
reserva-se para todos os objetos de uma forma seguida? Penso que deve ser a 1 opo.
Se tivermos apenas um objeto (ou varivel da estrutura) no necessrio darmos o nome da estrutura
struct {
char item[40]; // name of item
double cost; // cost
double retail; // retail price
int on_hand; // amount on hand
int lead_time; // number of days before resupply
} temp;
Estruturas
101
Acessar as variveis membro das estruturas
Agora queremos dar valores a cada uma das pessoas, queremos dar o nome e a altura, para isso faramos;
strcpy(p1.name, "Tiago");
p1.altura =1.9;
A forma genrica :
structure-varname.member-name
ou seja
[objecto_estrutura][member_estrutura]
Exemplo
#include <stdio.h>
const int MAX = 3;

struct Person
{
char name[100];
int height;
};

int main ()
{
Person p[MAX];
for (int x = 0; x < MAX; x++)
{
printf("Enter person's name: ");
getline(cin, p[x].name);
printf("Enter height in meters: ");
scanf("%d\n", &p[x].height);
}
printf("Outputting person data\n");
printf("======================\n");
for (int x = 0; x < MAX; x++){
printf("Person #%d's name is %s and height is %d.\n", x + 1, p[x].name, p[x].height);
}
return 0;
}
Estruturas
102
Iniciar uma estrutura
Podemos iniciar uma estrutura usando uma lista de iniciao, que seria algo como:
Person p1 = {"Jeff Kent", 72};
isto basicamente igual a arrays, apenas com a diferena de termos tipos diferentes. Logo a ordem vai interessar, por
exemplo se escrevssemos
Person p1 = {72, "Jeff Kent"}; //no iria funcionar- erro de compilao
Ponteiros para estruturas
struct movies_t
{
string title;
int year;
};

movies_t amovie;
movies_t * pmovie;
Ns crimos algo
movies_t title year
amovie
* pmovie
Vejamos que temos um ponteiro como instncia.
// pointers to structures
#include <stdio.h>

struct movies_t
{
char title[100];
int year;
};

int main ()
{
string mystr;
movies_t amovie;
movies_t *pmovie;
pmovie = &amovie; //atribumos valor ao ponteiro

printf("Enter title: ");
fgets(pmovie->title, 100, stdin); //operador ->
printf("Enter year: ";
scanf("%d", &pmovie->year);

printf("\nYou have entered:\n");
Estruturas
103
printf("%s (%d)\n", pmovie->title, pmovie->year); //operador ->
return 0;
}
Como j devem ter deduzido o operador -> ser muito similar a pmovie->title equivalente a (*pmovie).title
Mas olhem que diferente a:
*pmovie.title que equivalente a *(pmovie.title)
Passando estruturas como argumento de funes
A estrutura passada como ponteiro.
#include <stdio.h>
#include <string.h>

struct Person
{
string name;
int height;
};

void setValues(Person*);
void getValues(const Person*);

int main ()
{
Person p1;
setValues(&p1);
printf("Outputting person data\n");
printf("======================\n");
getValues(&p1);
return 0;
}

void setValues(Person* pers)
{
printf("Enter person's name: ");
fgets(pers.name, 100, stdin);
printf("Enter height in inches: ");
scanf("%d", &pers.height);
}

void getValues(const Person* pers)
{
printf("Person's name is %s and height is %d.", pers.name, pers.height);
}
Estruturas
104
Estruturas aninhadas
A ideia ter uma estrutura dentro de outra estrutura.
#include <stdio.h>

struct Date //estrutura chamada de date
{
int day;
int month;
int year;
};
struct Person
{
char name[100];
int height;
Date bDay; //temos uma nova varivel, mas notem o tipo
};

void setValues(Person*);
void getValues(const Person*);

int main ()
{
Person p1;
setValues(&p1);
printf("Outputting person data\n");
printf("======================\n");
getValues(&p1);
return 0;
}

void setValues(Person* pers)
{
printf("Enter person's name: ");
fgets(pers.name, 100, stdin);
printf("Enter height in inches: ");
scanf("%d", &pers.height);
printf("Enter day, month and year of birthday separated by spaces: ");
scanf("%d %d %d\n", &pers.bDay.day, &pers.bDay.month, &pers.bDay.year );
}

void getValues(const Person* pers)
{
printf("Person's name: %s\n", pers.name);
printf("Person's height in inches is: %d\n", pers.height);
printf("Person's birthday in dd/mm/yyyy format is: %d/%d/%d\n", pers.bDay.day, pers.bDay.month, pers.bDay.year );
}
Estruturas
105
Reparem que a estrutura Date tem de ser declarada antes da estrutura Person, pois caso contrrio o compilador no
entenderia o tipo declarado na estrutura Person.
Pergunta: Por que no podemos acrescentar mais membros (campos) nas estruturas?
Porque elas so compiladas estaticamente com posio de memria j alocada e tipo j conhecido em tempo de
compilao
Pergunta: Ao invs de termos apenas variveis nas estruturas, poderamos ter tambm funes?
Sim, como ponteiros para funes.
Ponteiros
Poderamos escrever um livro inteiro sobre ponteiros, pois o contedo demasiadamente extenso. Por esse motivo
este assunto foi dividido em bsico, intermedirio e avanado, assim o leitor poder fazer seus estudos conforme
suas necessidades.
recomendvel para quem est vendo programao pela primeira vez aqui que no se preocupe com o avanado
sobre ponteiros por enquanto.
Bsico
O que um ponteiro?
Um ponteiro simplesmente uma varivel que armazena o endereo de outra varivel.
Um exemplo : O que o ponteiro de um relgio? o que aponta para as horas, minutos ou segundos. Um ponteiro
aponta para algo. Em programao, temos as variveis armazenadas na memria, e um ponteiro aponta para um
endereo de memria.
Imagine as variveis como documentos, a memria do computador como pastas para guardar os documentos, e o
ponteiro como atalhos para as pastas.
No se desespere caso no consiga entender num primeiro momento, o conceito fica mais claro com a prtica.
Declarando e acessando ponteiros
Um ponteiro, como qualquer varivel, deve ter um tipo, que o tipo da varivel para a qual ele aponta. Para declarar
um ponteiro, especificamos o tipo da varivel para a qual ele aponta e seu nome precedido por asterisco:
int ponteiro ; /* declara uma varivel comum do tipo inteiro */
int *ponteiro ; /* declara um ponteiro para um inteiro */
Tome cuidado ao declarar vrios ponteiros em uma linha, pois o asterisco deve vir antes de cada nome de varivel.
Note os trs exemplos:
int p, q, r; // estamos a declarar trs variveis comuns
int *p, q, r; // cuidado! apenas p ser um ponteiro!
int *p, *q, *r; // agora sim temos trs ponteiros
Ponteiros
106
Esquema de um ponteiro
Para acessar o endereo de uma varivel, utilizamos
o operador & (E comercial), chamado "operador de
referncia" ou "operador de endereo". Como o
nome sugere, ele retorna o endereo na memria de
seu operando. Ele unrio e deve ser escrito antes
do seu operando. Por exemplo, se uma varivel
nome foi guardada no endereo de memria 1000, a
expresso &nome valer 1000.
Com isso, fica claro o esquema ao lado: a varivel
a contm o valor 1234 e o ponteiro p contem o endereo de a (&a).
Para atribuir um valor ao ponteiro, usamos apenas seu nome de varivel. Esse valor deve ser um endereo de
memria, portanto obtido com o operador &:
int a;
int *p;
p = &a;
Claro que tambm podemos inicializar um ponteiro:
int *p = &a;
Nos dois casos, o ponteiro p ir apontar para a varivel a.
Mas, como o ponteiro contm um endereo, podemos tambm atribuir um valor varivel guardada nesse endereo,
ou seja, varivel apontada pelo ponteiro. Para isso, usamos o operador * (asterisco), que basicamente significa
"o valor apontado por".
Ex:
int a ;
int *p = &a ;
*p = 20 ;
Para ver o resultado :
printf (" a :%i\n", a);
printf ("*p :%i\n", *p);
Cuidado! Voc nunca deve usar um ponteiro sem antes inicializ-lo; esse um erro comum. Inicialmente, um
ponteiro pode apontar para qualquer lugar da memria do computador. Ou seja, ao tentar ler ou gravar o valor
apontado por ele, voc estar manipulando um lugar desconhecido na memria!
int *p;
*p = 9;
Nesse exemplo, estamos a manipular um lugar desconhecido da memria! Se voc tentar compilar esse cdigo, o
compilador dever dar uma mensagem de aviso; durante a execuo, provavelmente ocorrer uma falha de
segmentao (erro que ocorre quando um programa tenta acessar a memria alheia).
Um exemplo mais elaborado:

#include <stdio.h>

int main()
Ponteiros
107
{
int i = 10 ;
int *p ;
p = &i ;
*p = 5 ;

printf ("%d\t%d\t%p\n", i, *p, p);
return 0;
}
Primeiramente declaramos a varivel i, com valor 10, e o ponteiro p, que apontar para o endereo de i. Depois,
guardamos o valor 5 no endereo apontado por p. Se voc executar esse exemplo, ver algo parecido com:
5 5 0022FF74
claro que os valores de i e de *p sero iguais, j que p aponta para i. O terceiro valor o endereo de memria
onde est i (e, consequentemente, o prprio valor de p), e ser diferente em cada sistema.
Cuidado! Os operadores unrios & e * no podem ser confundidos com os operadores binrios AND bit a bit e
multiplicao, respectivamente.
Ponteiro e NULL
Uma falha de segmentao ou em ingls (segmentation fault) ocorre quando um programa tenta acessar um endereo
na memria que est reservado ou que no existe.Nos sistemas Unix quando acontece este tipo de erro o sinal
SIGSEGV enviado ao programa indicando uma falha de segmentao.
Aqui o ponteiro contem null, definido com o endereo (0x00000000) que causa uma falha de segmentao .

/*Endereo invalido*/
#define null ( (char*) 0 )
int main(void){
int a = 5;
int *p = null;
*p = a;
}
Esse programa termina anormalmente. Voc esta tentando colocar o valor 5 em um endereo invlido.
Para que isso no acontea o ponteiro deve ser inicializado com um endereo valido. Exemplo :

#include <stdio.h>
#include <errno.h>
#include <stddef.h>
int main(void){
int a = 5;
int *p = NULL;
Ponteiros
108
p = &a;
/* A operao no permitida */
if(p == NULL) return -EPERM ;
else{
printf("Endereo a disposio:%p\n", p );
*p = a; /* Pode colocar 5 */
}
}
NULL est definido dentro do cabealho stddef.h . Aqui voc no espera que o programa acabe com algum tipo de
mgica, se NULL igual ao valor do ponteiro isso significa que no foi encontrado nem um endereo acessvel,
ento voc para. Caso contrario voc estar executando uma operao que no permitida. Ou colocar 5 em
(0x00000000) .
Mais operaes com ponteiros
Suponhamos dois ponteiros inicializados p1 e p2. Podemos fazer dois tipos de atribuio entre eles:
p1 = p2;
Esse primeiro exemplo far com que p1 aponte para o mesmo lugar que p2. Ou seja, usar p1 ser equivalente a
usar p2 aps essa atribuio.
*p1 = *p2;
Nesse segundo caso, estamos a igualar os valores apontados pelos dois ponteiros: alteraremos o valor apontado por
p1 para o valor apontado por p2.
Agora vamos dar mais alguns exemplos com o ponteiro p:
p++;
Aqui estamos a incrementar o ponteiro. Quando incrementamos um ponteiro ele passa a apontar para o prximo
valor do mesmo tipo em relao ao valor para o qual o ponteiro aponta. Isto , se temos um ponteiro para um inteiro
e o incrementamos, ele passa a apontar para o prximo inteiro. Note que o incremento no ocorre byte-a-byte!
(*p)++;
Aqui, colocamos *p entre parnteses para especificar que queremos alterar o valor apontado por p. Ou seja, aqui
iremos incrementar o contedo da varivel apontada pelo ponteiro p.
*p++
Neste caso, o efeito no to claro quanto nos outros exemplos. A precedncia do operador ++ sobre o operador *
faz com que a expresso seja equivalente a (*p)++. O valor atual de p retornado ao operador *, e o valor de p
incrementado. Ou seja, obtemos o valor atual do ponteiro e j o fazemos apontar para o prximo valor.
x = *(p + 15);
Esta linha atribui a uma varivel x o contedo do dcimo-quinto inteiro adiante daquele apontado por p. Por
exemplo, suponhamos que tivssemos uma srie de variveis i0, i1, i2, i15 e que p apontasse para i0.
Nossa varivel x receberia o valor de i15.
Ponteiros
109
Tente acompanhar este exemplo dos dois tipos de atribuio de ponteiros:
int *a, *b, c = 4, d = 2;
a = &c; // a apontar para c
b = &d; // b apontar para d
*b = 8; // altero o valor existente na variavel d
*a = *b; // copio o valor de d (apontado por b)
// para c (apontado por a)
*a = 1; // altero o valor da varivel c
b = a; // b aponta para o mesmo lugar que a,
// ou seja, para c
*b = 0; // altero o valor de c
Intermedirio
Ponteiro de estrutura
Para comear e deixar mais claro definimos uma estrutura simples com dois campos.
struct {
int i;
double f;
} minha_estrutura;
O passo seguinte definir um ponteiro para essa estrutura.
struct minha_estrutura *p_minha_estrutura;
A partir do ponteiro podemos ter acesso a um campo da estrutura usando um seletor "->" (uma flecha).
p_minha_estrutura-> i = 1;
p_minha_estrutura-> f = 1.2;
O mesmo resultado pode ser optido da seguinte forma.
(*p_minha_estrutura).i = 1;
(*p_minha_estrutura).f = 1.2;
O operador cast tambm e bastante utilizado para estruturar reas de estoque temporrios (buffer). Os tipos dentro da
estrutura devem ser o mesmo do arranjo para evitar problemas de alinhamento.
A seguir um pequeno exemplo:

#include <stdio.h>
typedef struct estruturar{
char a ;
char b ;
};

int main()
{
char buffer[2] = {17, 4};
Ponteiros
110
estruturar *p;
p = (struct estruturar*) &buffer;

printf("a: %i b: %i", p->a,p->b);
getchar();
return 0;
}
Ponteiros como parmetros de funes
Comecemos por uma situao-problema: eu tenho 2 variveis e quero trocar o valor delas. Vamos comear com um
algoritmo simples, dentro da funo main():

#include <stdio.h>

int main()
{
int a = 5, b = 10, temp;
printf ("%d %d\n", a, b);

temp = a;
a = b;
b = temp;

printf ("%d %d\n", a, b);
return 0;
}
Esse exemplo funcionar exatamente como esperado: primeiramente ele imprimir "5 10" e depois ele imprimir "10
5". Mas e se quisermos trocar vrias vezes o valor de duas variveis? muito mais conveniente criar uma funo que
faa isso. Vamos fazer uma tentativa de implementao da funo swap (troca, em ingls):

#include <stdio.h>

void swap(int i, int j)
{
int temp;
temp = i;
i = j;
j = temp;
}

int main()
{
int a, b;
a = 5;
b = 10;
Ponteiros
111
printf ("%d %d\n", a, b);
swap (a, b);
printf ("%d %d\n", a, b);
return 0;
}
No entanto, o que queremos no ir acontecer. Voc ver que o programa imprime duas vezes "5 10". Por que isso
acontece? Lembre-se do escopo das variveis: as variveis a e b so locais funo main(), e quando as passamos
como argumentos para swap(), seus valores so copiados e passam a ser chamados de i e j; a troca ocorre entre i
e j, de modo que quando voltamos funo main() nada mudou.
Ento como poderamos fazer isso? Como so retornados dois valores, no podemos usar o valor de retorno de uma
funo. Mas existe uma alternativa: os ponteiros!

#include <stdio.h>

void swap (int *i, int *j)
{
int temp;
temp = *i;
*i = *j;
*j = temp;
}

int main ()
{
int a, b;
a = 5;
b = 10;
printf ("\n\nEles valem %d, %d\n", a, b);
swap (&a, &b);
printf ("\n\nEles agora valem %d, %d\n", a, b);
return 0;
}
Neste exemplo, definimos a funo swap() como uma funo que toma como argumentos dois ponteiros para
inteiros; a funo faz a troca entre os valores apontados pelos ponteiros. J na funo main(), passamos os
endereos das variveis para a funo swap(), de modo que a funo swap() possa modificar variveis locais de
outra funo. O nico possvel inconveniente que, quando usarmos a funo, teremos de lembrar de colocar um &
na frente das variveis que estivermos passando para a funo.
Se voc pensar bem, j vimos uma funo em que passamos os argumentos precedidos de &: a funo scanf()! Por
que fazemos isso? simples: chamamos a funo scanf() para que ela ponha nas nossas variveis valores digitados
pelo usurio. Ora, essas variveis so locais, e portanto s podem ser alteradas por outras funes atravs de
ponteiros!
Quando uma funo recebe como parmetros os endereos e no os valores das variveis, dizemos que estamos a
fazer uma chamada por referncia; o caso desse ltimo exemplo. Quando passamos diretamente os valores das
variveis para uma funo, dizemos que uma chamada por valor; foi o caso do segundo exemplo.
Ponteiros
112
Ponteiros e vetores
Em C, os elementos de um vetor so sempre guardados sequencialmente, a uma distncia fixa um do outro. Com
isso, possvel facilmente passar de um elemento a outro, percorrendo sempre uma mesma distncia para frente ou
para trs na memria. Dessa maneira, podemos usar ponteiros e a aritmtica de ponteiros para percorrer vetores. Na
verdade, vetores so ponteiros um uso particular dos ponteiros. Acompanhe o exemplo a seguir.

#include <stdio.h>

int main ()
{
int i;
int vetorTeste[3] = {4, 7, 1};
int *ptr = vetorTeste;

printf("%p\n", vetorTeste);
printf("%p\n", ptr);
printf("%p\n", &ptr);

for (i = 0; i < 3; i++)
{
printf("O endereo do ndice %d do vetor %p\n", i, &ptr[i]);
printf("O valor do ndice %d do vetor %d\n", i, ptr[i]);
}
return 0;
}
Comeamos declarando um vetor com trs elementos; depois, criamos um ponteiro para esse vetor. Mas repare que
no colocamos o operador de endereo em vetorTeste; fazemos isso porque um vetor j representa um endereo,
como voc pode verificar pelo resultado da primeira chamada a printf().
Como voc j viu anteriormente neste captulo, podemos usar a sintaxe *(ptr + 1) para acessar o inteiro
seguinte ao apontado pelo ponteiro ptr. Mas, se o ponteiro aponta para o vetor, o prximo inteiro na memria ser o
prximo elemento do vetor! De fato, em C as duas formas *(ptr + n) e ptr[n] so equivalentes.
No necessrio criar um ponteiro para usar essa sintaxe; como j vimos, o vetor em si j um ponteiro, de modo
que qualquer operao com ptr ser feita igualmente com vetorTeste. Todas as formas abaixo de acessar o segundo
elemento do vetor so equivalentes:
vetorTeste[1];
*(vetorTeste + 1);
ptr[1];
*(ptr + 1)
Veja mais este exemplo:

#include <stdio.h>

int main()
{
Ponteiros
113
int numbers[5];
int *p;
int n;

p = numbers;
*p = 10;
p++;
*p = 20;
p = &numbers[2];
*p = 30;
p = numbers + 3;
*p = 40;
p = numbers;
*(p + 4) = 50;

for (n = 0; n < 5; n++)
cout << numbers[n] << ", ";
return 0;
}
Ele resume as vrias formas de acessar elementos de um vetor usando ponteiros.
Indexao estranha de ponteiros
o C permite fazer um tipo indexao de um vetor quando uma varivel controla seu ndice. O seguinte cdigo
vlido e funciona: Observe a indexao vetor[i].
#include <stdio.h>
int main ()
{
int i;
int vetor[10];
for (i = 0; i < 10; i++) {
printf ("Digite um valor para a posicao %d do vetor: ", i + 1);
scanf ("%d", &vetor[i]); //isso equivalente a fazer *(x + i)
}

for (i = 0; i < 10; i++)
printf ("%d\n", vetor[i]);
return (0);
}
Essa indexao, apesar de estranha, funciona corretamente e sem aviso na compilao. Ela prtica, mas, para os
iniciantes, pode parecer complicada. s treinar para entender.
Ponteiros
114
Comparando endereos
Como os endereos so nmeros, eles tambm podem ser comparados entre si. Veja o exemplo a seguir, com efeito
equivalente ao primeiro exemplo da seo anterior:

#include <stdio.h>

int main()
{
int vetorTeste[3] = {4, 7, 1};
int *ptr = vetorTeste;
int i = 0;

while (ptr <= &vetorTeste[2])
{
printf("O endereo do ndice %d do vetor %p\n", i, ptr);
printf("O valor do ndice %d do vetor %d\n", i, *ptr);
ptr++;
i++;
}
return 0;
}
Esse programa incrementa o ponteiro enquanto esse endereo for igual (ou menor) ao endereo do ltimo elemento
do vetor (lembre-se que os ndices do vetor so 0, 1 e 2).
Avanado
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
Este mdulo tem a seguinte tarefa pendente: mover o que de C++ para o livro de C++
Ponteiros para ponteiros
Acompanhe este exemplo:
char a;
char *b;
char **c;
a = 'z';
b = &a;
c = &b;
**c = 'M';

#include <stdlib.h>
#include<stdio.h>
Ponteiros
115
int vInt = 10;
int *pInt = &vInt;
int **pInt2 = &pInt;
int ***pInt3 = &pInt2;
int x=0;
int main(void){
printf("+-----------------+\n");
printf("| vInt |\n");
printf("+-----------------+\n");
printf("|%17d|\n",vInt);
printf("|%17p|<-+\n",&vInt);
printf("+-----------------+ |\n");
printf("| pInt | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt);
printf("|%17p|<-+\n",&pInt);
printf("|%17d| |\n",*pInt);
printf("+-----------------+ |\n");
printf("| pInt2 | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt2);
printf("|%17p|<-+\n",&pInt2);
printf("|%17d| |\n",**pInt2);
printf("+-----------------+ |\n");
printf("| pInt3 | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt3);
printf("|%17p|\n",&pInt3);
printf("|%17d|\n",***pInt3);
printf("+-----------------+\n");

***pInt3 = 76;
printf("+-----------------+\n");
printf("| vInt |\n");
printf("+-----------------+\n");
printf("|%17d|\n",vInt);
printf("|%17p|<-+\n",&vInt);
printf("+-----------------+ |\n");
printf("| pInt | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt);
printf("|%17p|<-+\n",&pInt);
printf("|%17d| |\n",*pInt);
printf("+-----------------+ |\n");
Ponteiros
116
printf("| pInt2 | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt2);
printf("|%17p|<-+\n",&pInt2);
printf("|%17d| |\n",**pInt2);
printf("+-----------------+ |\n");
printf("| pInt3 | |\n");
printf("+-----------------+ |\n");
printf("|%17p|--+\n",pInt3);
printf("|%17p|\n",&pInt3);
printf("|%17d|\n",***pInt3);
printf("+-----------------+\n");


// importante ressaltar que o valor de vInt foi modificado pois
a indireo mltipla a modoficou.

printf("+----------------------------------------------------------------+");
printf("| PROGRAMA FEITO POR : DANIEL CAMPOS DINIZ -
dinizdc@gmail.com |\n");

printf("+----------------------------------------------------------------+");

return 0;
}
Perceba que temos dois "nveis": c aponta para b, e b aponta para a. Assim, para acessar a usando o ponteiro c,
necessrio usar duas vezes o operador *: uma para obter o valor de b (cujo endereo est guardado em c), e a outra
para obter o valor de a, apontado por b.
Uma aplicao de ponteiros para ponteiros est nas strings, j que strings so vetores, que por sua vez so ponteiros.
Um vetor de strings seria justamente um ponteiro para um ponteiro.
Este mdulo tem a seguinte tarefa pendente: Criar cdigo exemplo sobre ponteiro para ponteiro
Passando vetores como argumentos de funes
Os ponteiros podem ser passados como argumentos de funes.
Parmetro ponteiro passando um array.

#include <stdio.h>

void atribuiValores(int[], int);
void mostraValores(int[], int);

int main()
{
Ponteiros
117
int vetorTeste[3]; // crio um vetor sem atribuir valores
atribuiValores(vetorTeste, 3);
mostraValores(vetorTeste, 3);
return 0;
}

void atribuiValores(int valores[], int num)
{
for (int i = 0; i < num; i++)
{
printf("Insira valor #%d: ", i + 1);
scanf("%d", &valores[i]);
}
}

void mostraValores(int valores[], int num)
{
for (int i = 0; i < num; i++)
{
printf("Valor #%d: %d\n", i + 1, valores[i]);
}
}
Repare que passamos dois parmetros para as funes:
1. 1. O "nome" do vetor, que representa o seu endereo na memria. (Temos 3 maneiras para passar o endereo do
vetor: diretamente pelo seu "nome", via um ponteiro ou pelo endereo do primeiro elemento.)
2. 2. Uma constante, que representa o nmero de elementos do vetor. Isso importante pois o C no guarda
informaes sobre o tamanho dos vetores; voc no deve tentar alterar ou acessar valores que no pertencem ao
vetor.
claro que devemos passar o endereo do vetor (por "referncia"), pois os seus valores so alterados pela funo
atribuiValores. De nada adiantaria passar o vetor por valor, pois o valor s seria alterado localmente na funo (como
j vimos no caso de troca do valor de duas variveis).
Por causa dessa equivalncia entre vetores e ponteiros, podemos fazer uma pequena alterao no prottipo (tanto na
declarao quanto na definio) das funes atribuiValores e mostraValores, sem precisar alterar o cdigo interno
dessas funes ou a chamada a elas dentro da funo main ? trocando
void atribuiValores(int[], int);
void mostraValores(int[], int);
por
void atribuiValores(int*, int);
void mostraValores(int*, int);
Para o compilador, voc no fez mudana alguma, justamente por conta dessa equivalncia. Em ambos os casos, foi
passado o endereo do vetor para as funes.
Ponteiros
118
Ponteiros para funes
Os ponteiros para funes servem, geralmente, para passar uma funo como argumento de uma outra funo. Neste
exemplo

#include <stdio.h>

int soma(int a, int b)
{
return (a + b);
}

int operacao(int x, int y, int (*func)(int,int))
{
int g;
g = (*func)(x, y);
return (g);
}

int main ()
{
int m;
m = operacao(7, 5, soma);
printf("%d\n", m);
return 0;
}
Veja que criamos uma funo que retorna a soma dos dois inteiros a ela fornecidos; no entanto, ela no chamada
diretamente. Ela chamada pela funo operacao, atravs de um ponteiro. A funo main passa a funo soma como
argumento para operacao, e a funo operacao chama essa funo que lhe foi dada como argumento.
Note bem o terceiro argumento da funo operacao: ele um ponteiro para uma funo. Nesse caso, ele foi
declarado como um ponteiro para uma funo que toma dois inteiros como argumentos e retorna outro inteiro. O *
indica que estamos declarando um ponteiro, e no uma funo. Os parnteses em torno de *func so essenciais,
pois sem eles o compilador entenderia o argumento como uma funo que retorna um ponteiro para um inteiro.
A forma geral para declarar um ponteiro para uma funo :
tipo_retorno (*nome_do_ponteiro)(lista de argumentos)
Para chamar a funo apontada pelo ponteiro, h duas sintaxes. A sintaxe original
(*nome_do_ponteiro)(argumentos);
Se ptr um ponteiro para uma funo, faz bastante sentido que a funo em si seja chamada por *ptr. No entanto, a
sintaxe mais moderna permite que ponteiros para funes sejam chamados exatamente da mesma maneira que
funes:
nome_do_ponteiro(argumentos);
Por fim, para inicializar um ponteiro para funo, no precisamos usar o operador de endereo (ele j est implcito).
Por isso, quando chamamos a funo operacao, no precisamos escrever &soma.
Ponteiros
119
Veja mais um exemplo na verdade, uma extenso do exemplo anterior:

#include <stdio.h>

int soma(int a, int b)
{
return (a+b);
}

int subtracao(int a, int b)
{
return (a-b);
}

int (*menos)(int, int) = subtracao;

int operacao(int x, int y, int (*func)(int,int))
{
int g;
g = func(x, y);
return (g);
}

int main()
{
int m, n;
m = operacao(7, 5, soma);
n = operacao(20, m, menos);
printf("%d\n", n);
return 0;
}
Aqui, criamos mais uma funo, subtracao, alm de criar um outro ponteiro para ela (uma espcie de "atalho"),
menos. Na funo main, referimo-nos funo de subtrao atravs desse atalho.
Veja tambm que aqui usamos a sintaxe moderna para a chamada de ponteiros de funes, ao contrrio do exemplo
anterior.
Mais sobre variveis
120
Mais sobre variveis
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
typedef
A instruo typedef serve para definir um novo nome para um certo tipo de dados intrnseco da linguagem ou
definido pelo usurio. Por exemplo, se fizssemos a seguinte declarao:
typedef unsigned int uint;
poderamos declarar variveis inteiras sem sinal (unsigned int) da seguinte maneira:
uint numero;
// equivalente a "unsigned int numero;"
Como exemplo vamos dar o nome de inteiro para o tipo int:
typedef int inteiro;
Como se v, typedef cria uma espcie de "apelido" para um tipo de dados, permitindo que esse tipo seja referenciado
atravs desse apelido em vez de seu identificador normal.
Um dos usos mais comuns de typedef abreviar a declarao de tipos complexos, como structs ou estruturas. Veja
este exemplo:
struct pessoa {
char nome[40];
int idade;
};
struct pessoa joao;
Observe que, para declarar a varivel joao, precisamos escrever a palavra struct. Podemos usar typedef para
abreviar essa escrita:
typedef struct _pessoa {
char nome[40];
int idade;
} Pessoa;
Pessoa joao;
Um "apelido" de tipo utilizado com bastante frequncia, embora no costumemos dar por isso: o tipo FILE,
usado nas funes de entrada/sada de arquivos.
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
Mais sobre variveis
121
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
Ento, quando declaramos algo como
FILE *fp;
na verdade estamos a declarar um ponteiro para uma estrutura, que ser preenchida mais tarde pela funo fopen.
Ateno! Voc no deve tentar manipular uma estrutura do tipo FILE; sua composio foi apresentada apenas como
exemplo ou ilustrao.
sizeof
O operador sizeof usado para se saber o tamanho de variveis ou de tipos. Ele retorna o tamanho do tipo ou
varivel em bytes como uma contante. Devemos us-lo para garantir portabilidade. Por exemplo, o tamanho de um
inteiro pode depender do sistema para o qual se est compilando. O sizeof um operador porque ele substitudo
pelo tamanho do tipo ou varivel no momento da compilao. Ele no uma funo. O sizeof admite duas formas:
sizeof nome_da_varivel
sizeof (nome_do_tipo)
Se quisermos ento saber o tamanho de um float fazemos sizeof(float). Se declararmos a varivel f como float e
quisermos saber o seu tamanho faremos sizeof f. O operador sizeof tambm funciona com estruturas, unies e
enumeraes.
Outra aplicao importante do operador sizeof para se saber o tamanho de tipos definidos pelo usurio. Seria, por
exemplo, uma tarefa um tanto complicada a de alocar a memria para um ponteiro para a estrutura ficha_pessoal,
criada na primeira pgina desta aula, se no fosse o uso de sizeof. Veja o exemplo:
typedef struct {
const char *nome;
const char *sobrenome;
int idade;
} Pessoa;
int main(void)
{
Pessoa *joaquim;
joaquim = malloc(sizeof(Pessoa));
joaquim->nome = "Joaquim";
joaquim->sobrenome = "Silva";
joaquim->idade = 15;
}
Outro exemplo:
#include <string.h>
#include <stdio.h>
Mais sobre variveis
122
int
main(void)
{
char *nome;
nome = malloc(sizeof(char) * 10);
sprintf(nome, "wikibooks");
printf("Site: http://pt.%s.org/", nome);
/*
Imprime:
Site: http://pt.wikibooks.org/
*/
}
A sentena abaixo NO funciona, pois sizeof substitudo pelo tamanho de um tipo em tempo de compilao.
const char *FRASE;
FRASE = "Wikibooks eh legal";
printf("Eu acho que o tamanho da string FRASE %d", sizeof(FRASE));
Converso de tipos
As atribuies no C tem o seguinte formato:
destino=origem;
Se o destino e a origem so de tipos diferentes o compilador faz uma converso entre os tipos. Mas nem todas as
converses so possveis. O primeiro ponto a ser ressaltado que o valor de origem convertido para o valor de
destino antes de ser atribudo e no o contrrio.
Em C, cada tipo bsico ocupa uma determinada poro de bits na memria, logo, a converso entre tipos nem
sempre algo nativo da linguagem, por assim dizer. H funes como atol e atof que convertem string em inteiro
longo (long int) e string em double, respectivamente. Mas em muitos casos possvel usar o casting.
importante lembrar que quando convertemos um tipo numrico para outro, ns nunca ganhamos preciso. Ns
podemos perder preciso ou no mximo manter a preciso anterior. Isto pode ser entendido de uma outra forma.
Quando convertemos um nmero no estamos introduzindo no sistema nenhuma informao adicional. Isto implica
que nunca vamos ganhar preciso.
Abaixo vemos uma tabela de converses numricas com perda de preciso, para um compilador com palavra de 16
bits:
De Para Informao Perdida
unsigned char char Valores maiores que 127 so alterados
short int char Os 8 bits de mais alta ordem
int char Os 8 bits de mais alta ordem
long int char Os 24 bits de mais alta ordem
long int short int Os 16 bits de mais alta ordem
long int int Os 16 bits de mais alta ordem
float int Preciso - resultado arredondado
double float Preciso - resultado arredondado
long double double Preciso - resultado arredondado
Mais sobre variveis
123
Casting: converso manual
Se declararmos a = 10/3, sabemos que o resultado 3,333, ou seja a diviso de dois nmeros inteiros d um nmero
real. Porm o resultado em C ser o inteiro 3. Isso acontece, porque as constantes so do tipo inteiro e operaes com
inteiros tem resultado inteiro. O mesmo ocorreria em a = b/c se b e c forem inteiros.
Se declararmos:
int a;
O resultado ser 3.
Mesmo que declarssemos:
float a;
o resultado continua a ser 3 mas desta vez, 3,0000.
Para fazer diviso que resulte nmero real, necessrio fazer cast para um tipo de ponto flutuante:
a = (float)10/3
a = 10/(float)3
Nesse caso, o 10 ou o 3 convertido para float. O outro nmero continua como inteiro, mas ao entrar na diviso com
um float, ele convertido automaticamente para float. A diviso feita e depois atribuda varivel a.
Em poucas palavras, casting colocar um tipo entre parnteses antes da atribuio de uma varivel. A forma geral
para cast :
(tipo)varivel
(tipo)(expresso)
variavel_destino = (tipo)variavel_origem;
Mas existem umas converses automticas:
int f(void)
{
float f_var;
double d_var;
long double l_d_var;
f_var = 1; d_var = 1; l_d_var = 1;
d_var = d_var + f_var; /*o float convertido em double*/
l_d_var = d_var + f_var; /*o float e o double convertidos em
long double*/
return l_d_var;
}
Repare que a converso feita de menor para o maior.
possvel fazer a converso ao contrrio de um tipo com mais bits para um com menos bits e isso truncar. Nesse
caso, o cast explcito necessrio. Assim, um nmero float: 43.023 ao ser convertido para int dever ser "cortado",
ficando inteiro: 43. Se converter long para short, os bits mais significativos so perdidos na converso.
O operador cast tambm e bastante utilizado para estruturar reas de estoque temporrios (buffer). A seguir um
pequeno exemplo:
#include <stdio.h>
typedef struct estruturar{
Mais sobre variveis
124
char a ;
char b ;
};

int main()
{
char buffer[2] = {17, 4};
estruturar *p;
p = (struct estruturar*) &buffer;
char* x = (char*)malloc(10);

printf("a: %i b: %i", p->a,p->b);
getchar();
return 0;
}
Atributos das variveis
Estes modificadores, como o prprio nome indica, mudam a maneira com a qual a varivel acessada e modificada.
Alguns dos exemplos usam conceitos que s sero abordados nas sees seguintes, ento voc pode deixar esta
seo para depois se assim o desejar.
const
O modificador const faz com que a varivel no possa ser modificada no programa. Como o nome j sugere til
para se declarar constantes. Poderamos ter, por exemplo:
const float PI = 3.1415;
Podemos ver pelo exemplo que as variveis com o modificador const podem ser inicializadas. Mas PI no poderia
ser alterado em qualquer outra parte do programa. Se o programador tentar modificar PI o compilador gerar um erro
de compilao.
Outro uso de const, alis muito comum que o outro, evitar que um parmetro de uma funo seja alterado pela
funo. Isto muito til no caso de um ponteiro, pois o contedo de um ponteiro pode ser alterado por uma funo.
Para proteger o ponteiro contra alteraes, basta declarar o parmetro como const.
#include <stdio.h>
int sqr (const int *num);
int main(void)
{
int a = 10;
int b;
b = sqr(&a);
}
int sqr (const int *num)
{
return ((*num)*(*num));
Mais sobre variveis
125
}
No exemplo, num est protegido contra alteraes. Isto quer dizer que, se tentssemos fazer
*num = 10;
dentro da funo sqr(), o compilador daria uma mensagem de erro.
volatile
O modificador volatile diz ao compilador que a varivel em questo pode ser alterada sem que este seja
avisado. Isto evita "bugs" que poderiam ocorrer se o compilador tentasse fazer uma otimizao no cdigo que no
segura quando a memria modificada externamente.
Digamos que, por exemplo, tenhamos uma varivel que o BIOS do computador altera de minuto em minuto (um
relgio, por exemplo). Seria importante que declarssemos esta varivel como volatile.
Um uso importante de variveis volatile em aplicaes com vrias threads (linhas de execuo), onde a
memria compartilhada por vrios pedaos de cdigo que so executados simultaneamente.
extern
O modificador extern diz ao compilador que a varivel indicada foi declarada em outro arquivo que no podemos
incluir diretamente, por exemplo o cdigo de uma biblioteca padro. Isso importante pois, se no colocarmos o
modificador extern, o compilador ir declarar uma nova varivel com o nome especificado, "ocultando" a varivel
que realmente desejamos usar. E se simplesmente no declarssemos a varivel, j sabemos que o compilador no
saberia o tamanho da varivel.
Quando o compilador encontra o modificador extern, ele marca a varivel como no resolvida, e o montador se
encarregar de substituir o endereo correto da varivel.
extern float sum;
extern int count;
float returnSum (void)
{
count++;
return sum;
}
Neste exemplo, o compilador ir saber que count e sum esto sendo usados no arquivo mas que foram declarados
em outro.
Uma varivel externa frequentemente usada a varivel errno (declarada no arquivo-cabealho errno.h), que
indica o ltimo cdigo de erro encontrado na execuo de uma funo da biblioteca padro ou do sistema.
static
O funcionamento das variveis declaradas como static depende de se estas so globais ou locais.
Variveis globais static funcionam como variveis globais dentro de um mdulo, ou seja, so variveis
globais que no so (e nem podem ser) conhecidas em outros mdulos (arquivos). Isto util se quisermos isolar
pedaos de um programa para evitar mudanas acidentais em variveis globais. Isso um tipo de encapsulamento
que , simplificadamente, o ato de no permitir que uma varivel seja modificada diretamente, mas apenas por
meio de uma funo.
Mais sobre variveis
126
Variveis locais estticas so variveis cujo valor mantido de uma chamada da funo para a outra. Veja o
exemplo:
int count (void)
{
static int num = 0;
num++;
return num;
}
A funo count() retorna o nmero de vezes que ela j foi chamada. Veja que a varivel local int inicializada. Esta
inicializao s vale para a primeira vez que a funo chamada pois num deve manter o seu valor de uma chamada
para a outra. O que a funo faz incrementar num a cada chamada e retornar o seu valor. A melhor maneira de se
entender esta varivel local static implementando. Veja por si mesmo, executando seu prprio programa que use
este conceito.
register
O computador pode guardar dados na memria (RAM) e nos registradores internos do processador. As variveis
(assim como o programa como um todo) costumam ser armazenadas na memria. O modificador register diz ao
compilador que a varivel em questo deve ser, se possvel, guardada em um registrador da CPU.
Vamos agora ressaltar vrios pontos importantes:
Porque usar register? Variveis nos registradores da CPU vo ser acessadas em um tempo muito menor
pois os registradores so muito mais rpidos que a memria. No entanto, a maioria dos compiladores otimizantes
atuais usa registradores da CPU para variveis, ento o uso de register freqentemente desnecessrio.
Em que tipo de varivel podemos usar o register? Antes da criao do padro ANSI C, register
aplicava-se apenas aos tipos int e char, mas o padro atual permite o uso de register para qualquer um
dos quatro tipos fundamentais. claro que seqncias de caracteres, arrays e estruturas tambm no podem ser
guardadas nos registradores da CPU por serem grandes demais.
register um pedido que o programador faz ao compilador. Este no precisa ser atendido necessariamente,
e alguns compiladores at ignoram o modificador register, o que permitido pelo padro C.
register no pode ser usado em variveis globais, pois isto implicaria em um registrador da CPU ficar o
tempo todo ocupado por essa varivel.
Um exemplo do uso do register dado a seguir:
int main (void)
{
register int count;
for (count = 0; count < 10; count++)
{
...
}
return 0;
}
O loop acima, em compiladores que no guardam variveis em registradores por padro, deve ser executado mais
rapidamente do que seria se no usssemos o register. Este o uso mais recomendvel para o register: uma varivel
que ser usada muitas vezes em seguida.
Mais sobre variveis
127
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.
Mais sobre funes
Os argumentos argc e argv
A funo main(), como dissemos antes, uma funo especial. Introduzimo-la como uma funo sem parmetros; no
entanto, ela tambm pode receber parmetros formais. No entanto, o programador no pode escolher quais sero.
Eles devem ser os seguintes:
int main (int argc, char *argv[])
argc (argument count) um inteiro e possui o nmero de argumentos com os quais o programa foi chamado na
linha de comando. Ele no mnimo 1, pois o nome do programa contado como sendo o primeiro argumento.
argv (argument values) um ponteiro para uma matriz de strings (conceitos que sero abordados mais frente).
Cada string desta matriz um dos parmetros da linha de comando. argv[0] sempre aponta para o nome do
programa (que, como j foi dito, considerado o primeiro argumento). para saber quantos elementos temos em
argv que temos argc.
Como pode se imaginar, os nomes dos parmetros "argc" e "argv" podem ser mudados, mas por questo de
padronizao no se costuma modific-los.
Exemplo: Escreva um programa que faa uso dos parmetros argv e argc. O programa dever receber da linha de
comando o dia, ms e ano correntes, e imprimir a data em formato apropriado. Veja o exemplo, supondo que o
executvel se chame data:
data 19 04 99
O programa dever imprimir: 19 de abril de 1999
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
int mes;
char *nome_mes [] = {
"Janeiro", "Fevereiro", "Maro", "Abril", "Maio", "Junho",
"Julho", "Agosto", "Setembro", "Outubro", "Novembro",
"Dezembro"
};
if(argc == 4) /* Testa se o nmero de parmetros fornecidos est
correto,
o primeiro parmetro o nome do programa, o
segundo o dia,
o terceiro o mes e o quarto os dois ltimos
algarismos do ano */
{
mes = atoi(argv[2]); /* argv contem strings. A string referente
ao mes deve ser transformada
Mais sobre funes
128
em um numero inteiro. A funcao atoi esta
sendo usada para isto:
recebe a string e transforma no inteiro
equivalente */
if (mes<1 || mes>12) /* Testa se o mes e' valido */
printf("Erro!\nUso: data dia mes ano, todos inteiros");
else
printf("\n%s de %s de 19%s", argv[1], nome_mes[mes-1],
argv[3]);
}
else printf("Erro!\nUso: data dia mes ano, todos inteiros");
}
Lista de argumentos
Na linguagem C possvel funes como "printf" onde o nmero de argumentos podem variar. As reticncias ( ... )
indicam um numero varivel de argumentos ou argumentos com tipos varivel. Ex:
void f_erro(int n, char *fmt, ...);
Essa declarao indica que se deve fornecer pelo menos dois argumentos, um do tipo int e um do tipo char mais pode
se fornecer argumentos suplementares. Ou seja, "no h limites para sua criatividade"! Ex:
f_erro( 3, "Erro: misso impossvel ");
f_erro( valor, "%s %d\n", mensagem, errno);
E necessrio ter pelo menos um argumento antes dos pontos. Veja um exemplo incorreto.
void erreur(...);
O arquivo de cabealho stdarg.h declara um tipo va_list e define trs macros para manipular uma lista de argumentos
cuja quantidade e tipos so desconhecidos pela funo.
va_start, va_arg et va_end (va como variable argument)
Sintaxe:
#include <stdarg.h>
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
Descrio:
va_start:
A macro va_start inicializa ap para uso posterior por va_arg e va_end e deve ser chamada primeiro.
O parmetro last o nome do ltimo parmetro antes da lista de argumentos variveis, isto , o ltimo
parmetro o qual a funo conhee o tipo.
Porque o endereo deste parmetro pode ser usado na macro va_start, ele no deve ser declarado como uma
varivel register, ou como uma funo ou como um array.
va_arg:
Mais sobre funes
129
A macro va_arg retorna o primeiro argumento varivel e faz ap apontar o prximo argumento. O parmetro ap
aquele inicializado por va_start. O parmetro type um nome de tipo. Pode-se apontar para um objeto de um
tipo especfico simplesmente adicionando um * ao tipo.
O primeiro uso da macro va_arg aps a macro va_start retorna o argumento aps last. Chamadas sucessivas
retornam os valores dos outros argumentos.
Se no existe prximo argumento, ou se type no compatvel com o tipo do prximo argumento, erros
aleatrios ocorrero.
Se ap passado para uma funo que usa va_arg(ap,type) ento o valor de ap destrudo aps o retorno da
funo.
va_end:
Cada chamada de va_start deve ter uma chamada correspondente a va_end na mesma funo. Aps a chamada
de va_end a varivel ap destruda. Vrias chamadas com va_start e va_end aninhadas so possveis. va_end
pode ser uma macro ou uma funo.
Exemplo 1

/* Calcula a soma de n inteiros */
/* o ultimo argumento deve ser 0 */
#include <stdio.h>
#include <stdarg.h>
int soma(int n1, ...) {
va_list pa;
int som, n;

som = n1;
va_start(pa, n1);
while( (n = va_arg(pa, int)) != 0)
som = som + n;
va_end(pa);
return som;
}
main() {
printf("1 + 3 + 5 + 7 + 9 = %d\n", soma(1,3,5,7,9,0));
printf("1 + 1 = %d\n", soma(1,1,0));
return 0;
}
/*-- resultado ----------------------------
1 + 3 + 5 + 7 + 9 = 25
1 + 1 = 2
---------------------------------------------------------*/
Exemplo 2

#include <stdio.h>
#include <stdarg.h>
Mais sobre funes
130
void meu_printf(char *fmt, ...) {
va_list pa;
int n;
char *s, c;
float f;

va_start(pa, fmt);
while (*fmt != '\0') {
if ( *fmt == '%' ) {
/* (*++fmt) equivale a (*fmt = *fmt + 1 )*/
switch (*++fmt) {
case '%' : putchar('%'); break;
case 'c' : /* char*/
c = va_arg(pa, int);
putchar(c);
break;
case 'd' : /* int */
n = va_arg(pa, int);
printf("%d", n);
break;
case 'f' : /* float */
f = va_arg(pa, double); /* !!!!! */
printf("%f", f);
break;
case 's' : /* string */
s = va_arg(pa, char *);
for ( ; *s != '\0'; s++ )
putchar( *s );
break;
} /* end switch */
}
else
putchar( *fmt );
/*incrementa o ponteiro*/
fmt++;
}
va_end(pa);
}
int main() {
meu_printf("float = %f\n", (float) 1.2345);
meu_printf("int = %d char = %c String = %s\n", 123, 'A', "C
is beautiful !" );
return 0;
}
Bibliotecas
131
Bibliotecas
Bibliotecas
Bibliotecas so conjuntos de funes que foram feitas por algum e que podem ser usadas por outros programas sem
que nos preocupemos com o cdigo dessas funes.
Alm da vantagem de organizar o cdigo, bibliotecas tambm tm a vantagem de poderem ser utilizadas em vrios
programas sem necessidade de copiar grandes trechos de cdigo; basta dizer ao compilador que queremos adicionar
aquela biblioteca ao executvel.
Por exemplo, vamos tentar criar a nossa prpria biblioteca, com duas funes: uma para gerar nmeros
(pseudo-)aleatrios e uma para calcular o valor de pagamento de uma amortizao com juros compostos. Tambm
incluiremos uma funo para gerar um nmero inicial a partir da hora atual, o que far com que as seqncias de
nmeros no sejam sempre as mesmas.
Chamaremos a biblioteca de teste1.
#include <math.h>
#include <time.h>

int rand_seed = 10;

/* Gerador de nmeros pseudo-aleatrios */
int rand ()
{
rand_seed = rand_seed * 1103515245 + 12345;
return (unsigned int) (rand_seed / 65536) % 32768;
}

void init_seed ()
{
rand_seed = time (NULL);
}

/* Clculo do valor de cada pagamento de uma amortizao
* Dados: vp = valor presente;
* n = nmero de pagamentos;
* i = taxa de juros (em formato decimal)
*/
double vf (double vp, int n, double i)
{
return (vp * i * pow (1 + i, n - 1) /
(pow (1 + i, n) - 1));
}
As linhas acima so o arquivo do cdigo da nossa biblioteca. Abaixo est o cdigo de um programa que testar essa
biblioteca. Lembre-se de que os dois trechos devem estar em arquivos separados.
#include <stdio.h>

Bibliotecas
132
int main()
{
int r1, r2, n_pgtos;
double a_vista, juros, v_pgto;

r1 = rand ();
r2 = rand ();
printf ("Nmeros aleatrios: %d, %d\n\n", r1, r2);

printf (" Valor vista: ");
scanf ("%lf", &a_vista);
printf ("Nmero de pagamentos: ");
scanf ("%d", &n_pgtos);
printf (" Taxa de juros: ");
scanf ("%lf", &juros);
juros /= 100; /* converte a porcentagem em nmero */

v_pgto = vf (a_vista, n_pgtos, juros);

printf ("Valor de cada pagamento: %lf\n", v_pgto);

return 0;
}
Algo que voc deve ter notado que nesse arquivo no demos nenhuma informao sobre as funes vf e rand nele
usadas. Realmente, se voc tentar compilar o cdigo como est, o compilador dar um aviso; mas ao tentar criar o
executvel, o montador no poder continuar pois no recebeu nenhuma informao sobre onde as funes esto.
Para isso, precisamos realizar trs passos adicionais antes de compilar o programa teste:
1. Fazer um arquivo-cabealho com informaes sobre as funes. Esse arquivo ser incluido com a diretiva
#include, da mesma maneira que cabealhos padro como "stdio.h" ou "math.h".
2. 2. Compilar a biblioteca separadamente.
3. 3. Instruir o compilador/montador a procurar pela biblioteca ao compilar o programa teste.
O arquivo-cabealho
Arquivos-cabealho so arquivos que contm informaes que servem para o compilador reconhecer funes
("VER: convenes para chamadas a funes ou calling convention"), macros, tipos de dados e variveis que no
esto no arquivo sendo compilado. Esses arquivos costumam ter a extenso ".h" o caso, por exemplo, dos
cabealhos padro stdio.h e math.h. A letra H usada pois a inicial de header (cabealho em ingls).
Em uma biblioteca, os cabealhos contm, os prottipos das funes disponibilizadas pela biblioteca e, quando
necessrio, sobre os tipos de estruturas usados. Bibliotecas mais complexas costumam dividir essas funes entre
vrios arquivos.
Para fazer nosso prprio cabealho, precisamos colocar as declaraes das funes disponveis na biblioteca:
int rand ();
void init_seed ();
double vf (double, int, double);
Bibliotecas
133
Se voc se lembra da ltima lio, poder sugerir que coloquemos algumas linhas a mais:
#ifndef _TESTE1_H
#define _TESTE1_H

int rand ();
void init_seed ();
double vf (double, int, double);

#endif
Agora, sempre que precisarmos usar a biblioteca teste1, basta incluir o arquivo teste1.h no incio do nosso programa:
#include "teste1.h"
Note que se o cabealho estiver instalado nos diretrios padro do compilador ou do sistema, voc deve trocar as
aspas pelos sinais de menor/maior (< ... >).
Compilao da biblioteca
Tendo salvo o cdigo da biblioteca no arquivo teste1.c, voc deve compilar a biblioteca.
No GCC
Compile o arquivo-fonte normalmente, mas sem gerar o executvel:
gcc -c teste1.c -o libteste1.o
Crie o arquivo da biblioteca com o comando ar. Voc ainda no o conhece, mas a sintaxe simples: basta digitar
ar rv, seguido do nome do arquivo da biblioteca e depois dos nomes dos arquivos-objeto a serem includos
(separados por espaos). No GCC, as bibliotecas estticas costumam ter o nome "libnome.a".
ar rv libteste1.a libteste1.o
No MS Visual C++
No Visual C++, o nome padro das bibliotecas "nome.lib", assim como em vrios outros compiladores para
Windows. Nele, os comandos correspondentes aos dois passos acima so:
cl /c teste1.c
lib /out:teste1.lib teste1.obj
Compilao do programa
Aps criar o arquivo objeto libteste1.o com o comando ( gcc -c teste1.c -o libteste1.o ) e a
biblioteca esttica com o comando "ar" , voc deve instruir o compilador com as opes de edio de links para
poder inclu-la no seu programa:
No GCC:
gcc main.c -L. -l libteste1.a -o main.bin -lm
Note as opes que voc no conhecia: -L e -l . A primeira indica em que diretrio deve ser procurada a
biblioteca; o ponto indica o diretrio atual. Se essa opo for omitida, o compilador procurar apenas nos diretrios
padro. A segunda uma opo do editor de links indicando uma biblioteca a ser includa; o compilador procurar
Bibliotecas
134
pelo arquivo adicionando o prefixo lib e a extenso .a, da a necessidade de dar o nome "libteste1.a" biblioteca.
Mais bibliotecas podem ser includas como a -lm que neste caso serve para chamar a biblioteca math do math.h,
sem este comando ele poder apresentar um erro na hora da compilao.
No Visual C++:
link /out:main.exe main.obj teste1.lib
Note que nesse caso simplesmente especificamos os arquivos que devem ser montados. O diretrio de procura pode
ser especificado pela opo /libpath:diretrio.
Entrada e sada em arquivos
Trabalhando com arquivos
J vimos como podemos receber e enviar dados para usurio atravs do teclado e da tela; agora veremos tambm
como ler e gravar dados em arquivos, o que alis muito importante ou at essencial em muitas aplicaes.
Assim como as funes de entrada/sada padro (teclado e tela), as funes de entrada/sada em arquivos esto
declaradas no cabealho stdio.h que significa "STanDard Input-Output". Alis, as funes para manipulao de
arquivos so muito semelhantes s usadas para entrada/sada padro. Como j dissemos na seo sobre a entrada e
sada padres, a manipulao de arquivos tambm se d por meio de fluxos (streams).
Na manipulao de um arquivo, h basicamente trs etapas que precisam ser realizadas:
1. 1. abrir o arquivo;
2. 2. ler e/ou gravar os dados desejados;
3. 3. fechar o arquivo.
Em C, todas as operaes realizadas com arquivos envolvem seu identificador de fluxo, que uma varivel do tipo
FILE * (sobre o qual no cabe agora falar). Para declarar um identificador de fluxo, faa como se fosse uma
varivel normal:
FILE *fp; // no se esquea do asterisco!
Abrindo e fechando um arquivo
No surpreendentemente, a primeira coisa que se deve fazer para manipular um arquivo abri-lo. Para isso, usamos
a funo fopen(). Sua sintaxe :
FILE *fopen (char *nome_do_arquivo, char *modo_de_acesso);
O nome do arquivo deve ser uma string ou com o caminho completo (por exemplo,
/usr/share/appname/app.conf ou C:\Documentos\nomes.txt) ou o caminho em relao ao
diretrio atual (nomes.txt, ../app.conf) do arquivo que se deseja abrir ou criar.
O modo de acesso uma string que contm uma seqncia de caracteres que dizem se o arquivo ser aberto para
gravao ou leitura. Depois de aberto o arquivo, voc s poder executar os tipos de ao previstos pelo modo de
acesso: no poder ler de um arquivo que foi aberto somente para escrita, por exemplo. Os modos de acesso esto
descritos na tabela a seguir.
Entrada e sada em arquivos
135
Modo Significado
r Abre o arquivo somente para leitura. O arquivo deve existir. (O r vem do ingls read, ler)
r+ Abre o arquivo para leitura e escrita. O arquivo deve existir.
w Abre o arquivo somente para escrita no incio do arquivo. Apagar o contedo do arquivo se ele j existir, criar um arquivo novo se no
existir. (O w vem do ingls write, escrever)
w+ Abre o arquivo para escrita e leitura, apagando o contedo pr-existente.
a Abre o arquivo para escrita no final do arquivo. No apaga o contedo pr-existente. (O a vem do ingls append, adicionar, apender)
a+ Abre o arquivo para escrita no final do arquivo e leitura.
Em ambientes DOS/Windows, ao ler arquivos binrios (por exemplo, programas executveis ou certos tipos de
arquivos de dados), deve-se adicionar o caractere "b" ao final da string de modo (por exemplo, "wb" ou "r+b") para
que o arquivo seja lido/gravado corretamente.
Isso necessrio porque no modo texto (o padro quando no adicionado o b) ocorrem algumas tradues de
caracteres (por exemplo, a terminao de linha "\r\n" substituda apenas por "\n" na leitura) que poderiam afetar a
leitura/gravao dos arquivos binrios (indevidamente inserindo ou suprimindo caracteres).
O valor de retorno da funo fopen() muito importante! Ele o identificador do fluxo que voc abriu e s com
ele que voc conseguir ler e escrever no arquivo aberto.
Se houver um erro na abertura/criao do arquivo, a funo retornar o valor NULL. O erro geralmente acontece
por duas razes:
O arquivo no existe, caso tenha sido requisitado para leitura.
O usurio atual no tem permisso para abrir o arquivo com o modo de acesso pedido. Por exemplo, o arquivo
somente-leitura, ou est bloqueado para gravao por outro programa, ou pertence a outro usurio e no tem
permisso para ser lido por outros.
Ao terminar de usar um arquivo, voc deve fech-lo. Isso feito pela funo fclose():
int fclose (FILE *fluxo);
O nico argumento o identificador do fluxo (retornado por fopen). O valor de retorno indica o sucesso da
operao com o valor zero.
Fechar um arquivo faz com que qualquer caractere que tenha permanecido no "buffer" associado ao fluxo de sada
seja gravado. Mas, o que este "buffer"? Quando voc envia caracteres para serem gravados em um arquivo,
estes caracteres so armazenados temporariamente em uma rea de memria (o "buffer") em vez de serem
escritos em disco imediatamente. Quando o "buffer" estiver cheio, seu contedo escrito no disco de uma vez. A
razo para se fazer isto tem a ver com a eficincia nas leituras e gravaes de arquivos. Se, para cada caractere
que fssemos gravar, tivssemos que posicionar a cabea de gravao em um ponto especfico do disco, apenas
para gravar aquele caractere, as gravaes seriam muito lentas. Assim estas gravaes s sero efetuadas quando
houver um volume razovel de informaes a serem gravadas ou quando o arquivo for fechado.
A funo exit() fecha todos os arquivos que um programa tiver aberto.
A funo fflush() fora a gravao de todos os caracteres que esto no buffer para o arquivo.
Entrada e sada em arquivos
136
Exemplo
Um pequeno exemplo apenas para ilustrar a abertura e fechamento de arquivos:
#include <stdio.h>

int main()
{
FILE *fp;
fp = fopen ("README", "w");
if (fp == NULL) {
printf ("Houve um erro ao abrir o arquivo.\n");
return 1;
}
printf ("Arquivo README criado com sucesso.\n");
fclose (fp);
return 0;
}
Arquivos pr-definidos
Na biblioteca padro do C, existem alguns fluxos pr-definidos que no precisam (nem devem) ser abertos nem
fechados:
stdin: dispositivo de entrada padro (geralmente o teclado)
stdout: dispositivo de sada padro (geralmente o vdeo)
stderr: dispositivo de sada de erro padro (geralmente o vdeo)
stdaux: dispositivo de sada auxiliar (em muitos sistemas, associado porta serial)
stdprn: dispositivo de impresso padro (em muitos sistemas, associado porta paralela)
Escrevendo em arquivos
Para escrever em arquivos, h quatro funes, das quais trs so anlogas s usadas para sada padro:
Sada padro Arquivos Explicao
putchar fputc Imprime apenas um caractere.
puts fputs Imprime uma string diretamente, sem nenhuma formatao.
printf fprintf Imprime uma string formatada.
N/A fwrite Grava dados binrios para um arquivo.
A seguir apresentamos os prottipos dessas funes:
void fputc (int caractere, FILE *fluxo);
void fputs (char *string, FILE *fluxo);
void fprintf (FILE *fluxo, char *formatao, ...);
int fwrite (void *dados, int tamanho_do_elemento, int num_elementos, FILE *fluxo);
Sintaxe quase igual de printf(); s necessrio adicionar o identificador de fluxo no incio.
Entrada e sada em arquivos
137
fwrite
Esta funo envolve os conceitos de ponteiro e vetor, que s sero abordados mais tarde.
A funo fwrite() funciona como a sua companheira fread(), porm escreve no arquivo. Seu prottipo :
unsigned fwrite(void *buffer,int numero_de_bytes,int count,FILE *fp);
A funo retorna o nmero de itens escritos. Este valor ser igual a count a menos que ocorra algum erro. O exemplo
abaixo ilustra o uso de fwrite e fread para gravar e posteriormente ler uma varivel float em um arquivo binrio.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *pf;
float pi = 3.1415;
float pilido;
if((pf = fopen("arquivo.bin", "wb")) == NULL) /* Abre arquivo
binrio para escrita */
{
printf("Erro na abertura do arquivo");
exit(1);
}
if(fwrite(&pi, sizeof(float), 1,pf) != 1) /* Escreve a
varivel pi */
printf("Erro na escrita do arquivo");
fclose(pf); /* Fecha o arquivo
*/
if((pf = fopen("arquivo.bin", "rb")) == NULL) /* Abre o arquivo
novamente para leitura */
{
printf("Erro na abertura do arquivo");
exit(1);
}
if(fread(&pilido, sizeof(float), 1,pf) != 1) /* Le em pilido o
valor da varivel armazenada anteriormente */
printf("Erro na leitura do arquivo");
printf("\nO valor de PI, lido do arquivo e': %f", pilido);
fclose(pf);
return 0;
}
Nota-se o uso do operador sizeof, que retorna o tamanho em bytes da varivel ou do tipo de dados.
Entrada e sada em arquivos
138
fputc
A funo fputc a primeira funo de escrita de arquivo que veremos. Seu prottipo :
int fputc (int ch, FILE *fp);
Escreve um caractere no arquivo.O programa a seguir l uma string do teclado e escreve-a, caractere por caractere
em um arquivo em disco (o arquivo arquivo.txt, que ser aberto no diretrio corrente).
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char string[100];
int i;
fp = fopen("arquivo.txt","w"); /* Arquivo ASCII, para
escrita */
if(!fp)
{
printf( "Erro na abertura do arquivo");
exit(0);
}
printf("Entre com a string a ser gravada no arquivo:");
gets(string);
for(i=0; string[i]; i++) putc(string[i], fp); /* Grava a string,
caractere a caractere */
fclose(fp);
return 0;
}
Depois de executar este programa, verifique o contedo do arquivo arquivo.txt (voc pode usar qualquer editor de
textos). Voc ver que a string que voc digitou est armazenada nele.
Lendo de arquivos
Novamente, h quatro funes, das quais trs se assemelham s usadas para a sada padro:
Sada padro Arquivos Explicao
getchar fgetc Recebe apenas um caractere.
gets fgets L uma string (geralmente uma linha inteira).
scanf fscanf Recebe uma string formatada.
N/A fread L dados binrios de um arquivo.
int fgetc (FILE *fluxo);
void fgets (char *string, int tamanho, FILE *fluxo);
void fscanf (FILE *fluxo, char *formatao, ...);
int fread (void *dados, int tamanho_do_elemento, int num_elementos, FILE *fluxo);
Entrada e sada em arquivos
139
Este mdulo tem a seguinte tarefa pendente: criar exemplos de uso das funes
fgetc
Est funo requer como parmetro o indicador de fluxo do arquivo, retorna um caractere do arquivo ou EOF,
caso ocorra um erro ou o final do arquivo seja atingido, podendo ser verificado respectivamente por ferror e feof.
Exemplo:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fl;
int c;
if((fl = fopen("caminho/do/arquivo", "r")) == NULL)
{
perror("Erro: fopen");
exit(EXIT_FAILURE);
}
while((c = fgetc(fl)) != EOF)
printf("Caractere lido: %c\n", c);
if((c == EOF) && (feof(fl) == 0) && (ferror(fl) != 0))
perror("Erro: fgetc");

fclose(fl);
return EXIT_SUCCESS;
}
fgets
Ao chamar a funo fgets(), voc deve fornecer o ponteiro para a string onde os dados lidos devem ser guardados,
alm do tamanho mximo dos dados a serem lidos (para que a memria reservada string no seja ultrapassada).
Para se ler uma string num arquivo podemos usar fgets() cujo prottipo :
char *fgets (char *str, int tamanho,FILE *fp);
A funo recebe 3 argumentos: a string a ser lida, o limite mximo de caracteres a serem lidos e o ponteiro para
FILE, que est associado ao arquivo de onde a string ser lida. A funo l a string at que um caracter de nova linha
seja lido ou tamanho-1 caracteres tenham sido lidos. Se o caracter de nova linha ('\n') for lido, ele far parte da string,
o que no acontecia com gets.
A funo fgets semelhante funo gets(), porm, alm dela poder fazer a leitura a partir de um arquivo de dados e
incluir o caracter de nova linha na string, ela ainda especifica o tamanho mximo da string de entrada. Como vimos,
a funo gets no tinha este controle, o que poderia acarretar erros de "estouro de buffer". Portanto, levando em
conta que o ponteiro fp pode ser substitudo por stdin, como vimos acima, uma alternativa ao uso de gets usar a
Entrada e sada em arquivos
140
seguinte construo:
fgets (str, tamanho, stdin);
fscanf
Sintaxe quase igual de scanf(); s necessrio adicionar o identificador de fluxo no incio.
fscanf
A funo fscanf() funciona como a funo scanf(). A diferena que fscanf() l de um arquivo e no do teclado do
computador. Prottipo:
int fscanf (FILE *fp,char *str,...);
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *p;
char str[80],c;
printf("\n\n Entre com um nome para o arquivo:\n"); /* Le um
nome para o arquivo a ser aberto: */
gets(str);
if (!(p = fopen(str,"w"))) /* Caso
ocorra algum erro na abertura do arquivo..*/
{ /* o programa
aborta automaticamente */
printf("Erro! Impossivel abrir o arquivo!\n");
exit(1);
}
fprintf(p,"Este e um arquivo chamado:\n%s\n", str);
fclose(p); /* Se nao
houve erro, imprime no arquivo, fecha ...*/
p = fopen(str,"r"); /* abre
novamente para a leitura */
while (!feof(p))
{
fscanf(p,"%c",&c);
printf("%c",c);
}
fclose(p);
return 0;
}
Entrada e sada em arquivos
141
fread
Essa funo envolve os conceitos de ponteiro e vetor, que s sero abordados mais tarde.
Podemos escrever e ler blocos de dados. Para tanto, temos as funes fread() e fwrite(). O prottipo de fread() :
unsigned fread (void *buffer, int numero_de_bytes, int count, FILE *fp);
O buffer a regio de memria na qual sero armazenados os dados lidos. O nmero de bytes o tamanho da
unidade a ser lida. count indica quantas unidades devem ser lidas. Isto significa que o nmero total de bytes lidos :
numero_de_bytes*count
A funo retorna o nmero de unidades efetivamente lidas. Este nmero pode ser menor que count quando o fim do
arquivo for encontrado ou ocorrer algum erro.
Quando o arquivo for aberto para dados binrios, fread pode ler qualquer tipo de dados.
Movendo pelo arquivo
fseek
Para se fazer procuras e acessos randmicos em arquivos usa-se a funo fseek(). Esta move a posio corrente de
leitura ou escrita no arquivo de um valor especificado, a partir de um ponto especificado. Seu prottipo :
int fseek (FILE *fp, long numbytes, int origem);
O parmetro origem determina a partir de onde os numbytes de movimentao sero contados. Os valores possveis
so definidos por macros em stdio.h e so:
Nome Valor Significado
SEEK_SET 0 Incio do arquivo
SEEK_CUR 1 Ponto corrente no arquivo
SEEK_END 2 Fim do arquivo
Tendo-se definido a partir de onde ir se contar, numbytes determina quantos bytes de deslocamento sero dados na
posio atual.
rewind
Volta para o comeo do arquivo de um fluxo
feof
EOF ("End of file") indica o fim de um arquivo. s vezes, necessrio verificar se um arquivo chegou ao fim. Para
isto podemos usar a funo feof(). Ela retorna no-zero se o arquivo chegou ao EOF, caso contrrio retorna zero. Seu
prottipo :
int feof (FILE *fp);
Outra forma de se verificar se o final do arquivo foi atingido comparar o caractere lido por getc com EOF. O
programa a seguir abre um arquivo j existente e o l, caracter por caracter, at que o final do arquivo seja atingido.
Os caracteres lidos so apresentados na tela:
#include <stdio.h>
#include <stdlib.h>
Entrada e sada em arquivos
142
int main()
{
FILE *fp;
char c;
fp = fopen("arquivo.txt","r"); /* Arquivo ASCII, para leitura */
if(!fp)
{
printf( "Erro na abertura do arquivo");
exit(0);
}
while((c = getc(fp) ) != EOF) /* Enquanto no chegar ao final
do arquivo */
printf("%c", c); /* imprime o caracter lido */
fclose(fp);
return 0;
}
Verifique o exemplo.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *p;
char c, str[30], frase[80] = "Este e um arquivo chamado: ";
int i;
printf("\n\n Entre com um nome para o arquivo:\n");
gets(str); /* Le um nome para o
arquivo a ser aberto: */
if (!(p = fopen(str,"w"))) /* Caso ocorra algum erro na
abertura do arquivo..*/
{
printf("Erro! Impossivel abrir o arquivo!\n");
exit(1); /* o programa aborta automaticamente
*/
}
strcat(frase, str);
for (i=0; frase[i]; i++)
putc(frase[i],p);
fclose(p); /* Se nao houve erro,imprime no
arquivo e o fecha ...*/
p = fopen(str,"r"); /* Abre novamente para leitura
*/
c = getc(p); /* Le o primeiro caracter */
while (!feof(p)) /* Enquanto no se chegar no
final do arquivo */
Entrada e sada em arquivos
143
{
printf("%c",c); /* Imprime o caracter na tela */
c = getc(p); /* Le um novo caracter no arquivo */
}
fclose(p); /* Fecha o arquivo */
}
Outras funes
Funo Explicao
remove Remove um arquivo especificado
ferror e perror
Prottipo de ferror:
int ferror (FILE *fp);
A funo retorna zero, se nenhum erro ocorreu e um nmero diferente de zero se algum erro ocorreu durante o
acesso ao arquivo. se torna muito til quando queremos verificar se cada acesso a um arquivo teve sucesso, de modo
que consigamos garantir a integridade dos nossos dados. Na maioria dos casos, se um arquivo pode ser aberto, ele
pode ser lido ou gravado.
Porm, existem situaes em que isto no ocorre. Por exemplo, pode acabar o espao em disco enquanto gravamos,
ou o disco pode estar com problemas e no conseguimos ler, etc. Uma funo que pode ser usada em conjunto com
ferror() a funo perror() (print error), cujo argumento uma string que normalmente indica em que parte do
programa o problema ocorreu.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *pf;
char string[100];
if((pf = fopen("arquivo.txt","w")) ==NULL)
{
printf("\nNao consigo abrir o arquivo ! ");
exit(1);
}
do
{
printf("\nDigite uma nova string. Para terminar, digite <enter>: ");
gets(string);
fputs(string, pf);
putc('\n', pf);
if(ferror(pf))
{
perror("Erro na gravacao");
fclose(pf);
Entrada e sada em arquivos
144
exit(1);
}
}while (strlen(string) > 0);
fclose(pf);
}
Gerenciamento de memria
Alocao dinmica
Todos os dados de um programa so armazenados na memria do computador; muito comum necessitar reservar
um certo espao na memria para poder guardar dados mais tarde. Por exemplo, poderamos reservar um espao de
1000 bytes para guardar uma string que o usurio viesse a digitar, declarando um vetor de 1000 caracteres. E se
quisssemos reservar um espao que s conhecido no tempo de execuo do programa? E se o espao fosse muito
grande, de modo que declarar vetores de tal tamanho seria inconveniente (pois, entre outras coisas, aumenta sem
necessidade o tamanho do executvel)?
Para solucionar esse problema, existe a alocao dinmica de memria, que como o nome sugere, uma maneira
de alocar memria medida que o programa vai sendo executado. As quatro funes relacionadas com a alocao
dinmica sero descritas a seguir.
malloc e free
Essas duas funes so as mais bsicas para o gerenciamento de memria. malloc responsvel pela alocao de
um pedao de memria, e free responsvel por liberar esse pedao de memria.
A funo malloc() serve para alocar memria e tem o seguinte prottipo:
void *malloc (unsigned int num);
void free (void * ptr);
Para alocar um espao na memria, precisamos fornecer funo malloc o nmero de bytes desejados. Ela aloca
na memria e retorna um ponteiro void * para o primeiro byte alocado. O ponteiro void* pode ser atribudo a
qualquer tipo de ponteiro. Se no houver memria suficiente para alocar a memria requisitada a funo malloc()
retorna um ponteiro nulo.
Para saber o tamanho do bloco a alocar, precisaremos usar o operador sizeof. Ele permite tambm saber
automaticamente o tamanho de structs criadas pelo usurio.
Veja um exemplo de alocao dinmica:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

/* ponteiro para memria que ser alocada */
int *p;
int i;

Gerenciamento de memria
145
/* alocar 10 elementos inteiros, ou seja, ( sizeof (int) * 10 ) */
p = (int *) malloc ( sizeof (int) * 10);

if ( p == NULL ) {
printf ("Erro: No foi possivel alocar memria\n");
exit(1);
}

for(i = 0; i < 10; i++) {
p[i] = i * 2;
printf ("%d\n", p[i]);
}

/* libera a memria alocada por malloc */
free (p);

return 0;
}
Outros exemplos:
int main()
{
int *p, *q;
p = malloc(sizeof(int));
q = p;
*p = 10;
printf("%d\n", *q);
*q = 20;
printf("%d\n", *q);
}
int main()
{
int *p, *q;
p = malloc(sizeof(int));
q = malloc(sizeof(int));
*p = 10;
*q = 20;
*p = *q;
printf("%d\n", *p);
}
O compilador aceita *p=*q porque so ambos int.
O compilador aceita tambm p=q porque ambos so ponteiros e apontam para o mesmo tipo.
Podemos simplificar p = malloc(sizeof(int)); por p = malloc(4); mas como temos sistemas operacionais de 16,32,
64 bits a primeira declarao torna as coisas mais portveis.
Gerenciamento de memria
146
calloc
A funo calloc() tambm serve para alocar memria, mas possui um prottipo um pouco diferente:
void *calloc(size_t nelem, size_t elsize);
A funo calloc reserva um bloco com o tamanho (nelem x elsize) octetos consecutivos, isto , aloca memria
suficiente para um vetor de num objetos de tamanho size. Diferente de malloc(), o bloco reservado inicializado a 0.
Essa funo retorna um ponteiro void* para o primeiro byte alocado. O ponteiro void* pode ser atribudo a qualquer
tipo de ponteiro. Se no houver memria suficiente para alocar a memria requisitada a funo calloc() retorna um
ponteiro nulo.
Exemplo:
#include <stdio.h>
#include <stdlib.h> /* Para usar calloc() */
int main (){
int *p;
int n;
int i;
... /* Determina o valor de n em algum lugar
*/
p = calloc(n, sizeof(int)); /* Aloca n nmeros inteiros p pode
agora ser tratado como um vetor com n posicoes */
//p = malloc(n*sizeof(int)); /* Maneira equivalente usando malloc.
*/
if (!p)
{
printf ("** Erro: Memoria Insuficiente **");
exit(0);
}
for (i=0; i<n; i++) /* p pode ser tratado como um vetor com n posicoes */
p[i] = i*i;
...
return 0;
}
No exemplo acima, alocada memria suficiente para se colocar n nmeros inteiros. O operador sizeof() retorna o
nmero de bytes de um inteiro. Ele til para se saber o tamanho de tipos. O ponteiro void * que calloc() retorna
convertido para um int* pelo cast e atribudo a p. A declarao seguinte testa se a operao foi bem sucedida. Se
no tiver sido, p ter um valor nulo, o que far com que !p retorne verdadeiro. Se a operao tiver sido bem sucedida,
podemos usar o vetor de inteiros alocados normalmente, por exemplo, indexando-o de p[0] a p[(a-1)].
Gerenciamento de memria
147
realloc
A funo realloc() serve para realocar memria e tem o seguinte prottipo:
void *realloc(void *ptr, size_t size);
A funo realloc ajusta o tamanho de um bloco a size octetos consecutivos. A funo modifica o tamanho da
memria previamente alocada com malloc, calloc ou realloc e apontada por ptr para o tamanho especificado por size.
O valor de size pode ser maior ou menor que o original. Um ponteiro para o bloco devolvido porque realloc() pode
precisar mover o bloco para aumentar seu tamanho. Se isso ocorrer, o contedo do bloco antigo copiado no novo
bloco, o bloco antigo liberado e nenhuma informao perdida. Se no precisar mover, o valor retornado igual a
ptr. Se ptr for nulo, a funo aloca size bytes e devolve um ponteiro, funcionando como malloc(); se size zero, a
memria apontada por ptr liberada. Se no houver memria suficiente para a alocao, um ponteiro nulo
devolvido e o bloco original deixado inalterado.
Exemplo:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *str1=NULL, *str2=NULL;
str1 = (char *) malloc(11);
strcpy(str1, "ABCDEFGHIJ");
str2 = (char *) realloc(str2, 20);
printf("Endereo de str1 : %p\n", str1);
printf("Endereo de str2 : %p\n", str2);
str1 = (char *) realloc(str1, 100);
printf("Novo endereo de str1 : %p\n", str1);
printf("Conteudo de str1 : %s\n", str1);
free(str1);
free(str2);
return 0;
}
Alocao Dinmica de Vetores
A alocao dinmica de vetores utiliza os conceitos aprendidos na aula sobre ponteiros e as funes de alocao
dinmica apresentados. Um exemplo de implementao para vetor real fornecido a seguir:
#include <stdio.h>
#include <stdlib.h>
float *Alocar_vetor_real (int n)
{
float *v; /* ponteiro para o
Gerenciamento de memria
148
vetor */
if (n < 1)
{ /* verifica
parametros recebidos */
printf ("** Erro: Parametro invalido **\n");
return (NULL);
}
v = calloc (n, sizeof(float)); /* aloca o vetor */
if (v == NULL)
{
printf ("** Erro: Memoria Insuficiente **");
return (NULL);
}
return (v); /* retorna o ponteiro
para o vetor */
}
float *Liberar_vetor_real (float *v)
{
if (v == NULL) return (NULL);
free(v); /* libera o vetor */
return (NULL); /* retorna o ponteiro */
}
int main (void)
{
float *p;
int a;
... /* outros comandos, inclusive a
inicializacao de a
*/
p = Alocar_vetor_real (a);
... /* outros comandos, utilizando p[]
normalmente */
p = Liberar_vetor_real (p);
}
Alocao Dinmica de Matrizes
A alocao dinmica de memria para matrizes realizada da mesma forma que para vetores, com a diferena que
teremos um ponteiro apontando para outro ponteiro que aponta para o valor final, ou seja um ponteiro para
ponteiro, o que denominado indireo mltipla. A indireo mltipla pode ser levada a qualquer dimenso
desejada, mas raramente necessrio mais de um ponteiro para um ponteiro. Um exemplo de implementao para
matriz real bidimensional fornecido a seguir. A estrutura de dados utilizada neste exemplo composta por um
vetor de ponteiros (correspondendo ao primeiro ndice da matriz), sendo que cada ponteiro aponta para o incio de
uma linha da matriz. Em cada linha existe um vetor alocado dinamicamente, como descrito anteriormente
(compondo o segundo ndice da matriz).
#include <stdio.h>
#include <stdlib.h>
Gerenciamento de memria
149
float **Alocar_matriz_real (int m, int n)
{
float **v; /* ponteiro para a matriz */
int i; /* variavel auxiliar */
if (m < 1 || n < 1)
{ /* verifica parametros
recebidos */
printf ("** Erro: Parametro invalido **\n");
return (NULL);
} /* aloca as linhas da matriz */
v = calloc (m, sizeof(float *)); /*Um vetor de m ponteiros
para float */
if (v == NULL)
{
printf ("** Erro: Memoria Insuficiente **");
return (NULL);
}
for ( i = 0; i < m; i++ ) /* aloca as colunas da matriz */
{
v[i] = calloc (n, sizeof(float)); /* m vetores de n floats
*/
if (v[i] == NULL)
{
printf ("** Erro: Memoria Insuficiente **");
return (NULL);
}
}
return (v); /* retorna o ponteiro
para a matriz */
}
float **Liberar_matriz_real (int m, int n, float **v)
{
int i; /* variavel auxiliar */
if (v == NULL) return (NULL);
if (m < 1 || n < 1)
{ /* verifica parametros recebidos */
printf ("** Erro: Parametro invalido **\n");
return (v);
}
for (i=0; i<m; i++) free (v[i]); /* libera as linhas da matriz */
free (v); /* libera a matriz (vetor de
ponteiros) */
return (NULL); /* retorna um ponteiro nulo */
}
Gerenciamento de memria
150
int main (void)
{
float **mat; /* matriz a ser alocada */
int l, c; /* numero de linhas e colunas da matriz */
int i, j;
... /* outros comandos, inclusive inicializacao
para l e c */
mat = Alocar_matriz_real (l, c);
for (i = 0; i < l; i++)
for ( j = 0; j < c; j++)
mat[i][j] = i+j;
... /* outros comandos utilizando mat[][]
normalmente */
mat = Liberar_matriz_real (l, c, mat);
...
}
Sockets
Abstraes
A verso Unix BSD 4.1c de 1982 para VAX foi a primeira a incluir TCP/IP no kernel do sistema operacional,
oferecendo ao mesmo tempo uma interface de programao como abstrao para esses protocolos. Os soquetes ou
sockets so uma API (Application Program Interface) isso quer dizer uma interface entre os programas e a camada
de transporte. Exemplo: TCP, UDP. Os soquetes podem usar outros protocolos como AppleTalk, Xrox XNS, etc. A
API de sockets foi desenvolvida para a linguagem C e so uma das principais API para sistemas do tipo UNIX. O
Windows possui uma interface similar conhecida com o nome de Winsock.
Funes da biblioteca padro
int accept(int, struct sockaddr *restrict, socklen_t *restrict);
int bind(int, const struct sockaddr *, socklen_t);
int connect(int, const struct sockaddr *, socklen_t);
int getpeername(int, struct sockaddr *restrict, socklen_t
*restrict);
int getsockname(int, struct sockaddr *restrict, socklen_t
*restrict);
int getsockopt(int, int, int, void *restrict, socklen_t *restrict);
int listen(int, int);
ssize_t recv(int, void *, size_t, int);
ssize_t recvfrom(int, void *restrict, size_t, int,
struct sockaddr *restrict, socklen_t *restrict);
ssize_t recvmsg(int, struct msghdr *, int);
ssize_t send(int, const void *, size_t, int);
ssize_t sendmsg(int, const struct msghdr *, int);
ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *,
Sockets
151
socklen_t);
int setsockopt(int, int, int, const void *, socklen_t);
int shutdown(int, int);
int socket(int, int, int);
int sockatmark(int);
int socketpair(int, int, int, int[2]);
Famlias de endereo
Existem varias famlias de endereo e cada uma corresponde a um protocolo em particular.
As famlias mais usadas so :
AF_UNIX: Protocolo interno do UNIX
AF_INET: Protocolo Internet
AF_NS : Protocolo de Xerox NS
Estruturas de endereo
Varias chamada ao sistema de redes do unix precisam apontar para uma estrutura de endereo de socket.
A definio dessas estruturas esta definida dentro do cabealho <sys/socket.h>.
struct sockaddr {
u_short sa_family ;
char sa_data[14] ;
} ;
sa_family: Famlia de endereo leva o valor AF_xxx .
sa_data: endereo especifico de protocolo .
Para a famlia internet as estrutura esto definidas dentro do cabealho <netinet/in.h>.
struct in_addr {
u_long s_addr ;
} ;
struct sockaddr_in {
short sin_family ;
u_short sin_port ;
struct in_addr sin_addr ;
char sin_zero[8] ;
} ;
Makefiles
152
Makefiles
Makefile
O objetivo de Makefile definir regras de compilao para projetos de software. Tais regras so definidas em
arquivo chamado Makefile. O programa make interpreta o contedo do Makefile e executa as regras l definidas.
Alguns Sistemas Operacionais trazem programas similares ao make, tais como gmake, nmake, tmake, etc. O
programa make pode variar de um sistema a outro pois no faz parte de nenhuma normalizao .
O texto contido em um Makefile usado para a compilao, ligao(linking), montagem de arquivos de projeto entre
outras tarefas como limpeza de arquivos temporrios, execuo de comandos, etc.
Vantagens do uso do Makefile:
Evita a compilao de arquivos desnecessrios. Por exemplo, se seu programa utiliza 120 bibliotecas e voc altera
apenas uma, o make descobre (comparando as datas de alterao dos arquivos fontes com as dos arquivos
anteriormente compilados) qual arquivo foi alterado e compila apenas a biblioteca necessria.
Automatiza tarefas rotineiras como limpeza de vrios arquivos criados temporariamente na compilao
Pode ser usado como linguagem geral de script embora seja mais usado para compilao
As explicaes a seguir so para o utilitrio GNU make (gmake) que similar ao make.
Ento vamos para a apresentao do Makefile atravs da compilao de um pequeno projeto em linguagem C.
Criar uma pasta com esses 4 arquivos :
teste.c ,teste.h , main.c, Makefile.
De um nome para a pasta Projeto.
/*================ teste.c ======================*/
#include <stdio.h>
#include <stdlib.h>
/*Uma funao makeTeste()*/
void makeTeste(void){
printf("O Makefile super Legal\n");
}
Aqui escrevemos o header :
/*======================= teste.h ===============*/
/*================== Cabealho ou header ========*/
#ifndef _H_TESTE
#define _H_TESTE
/* A nossa funo */
void makeTeste(void);
/* De um enter depois de endif*/
/*Para evitar warning*/
#endif
Agora a funo main :
/*====================== main.c =================*/
#include <stdio.h>
#include <stdlib.h>
Makefiles
153
#include "teste.h"
/* Aqui main ;( */
int main(void){
makeTeste();
return (0);
}
Para compilar fazemos um arquivo Makefile minimal.
#Para escrever comentrios ##
############################# Makefile ##########################
all: teste
teste: teste.o main.o
# O compilador faz a ligao entre os dois objetos
gcc -o teste teste.o main.o
#-----> Distancia com o boto TAB ### e no com espaos
teste.o: teste.c
gcc -o teste.o -c teste.c -W -Wall -ansi -pedantic
main.o: main.c teste.h
gcc -o main.o -c main.c -W -Wall -ansi -pedantic
clean:
rm -rf *.o
mrproper: clean
rm -rf teste
Para no ter erros os espaos devem ser feito com a tecla TAB.
E compilar s ir dentro da pasta "Projeto" apertar F4 escrever make e apertar enter.
Uma vez compilado podemos modificar teste.c . Se teste.c foi modificado ento make modifica teste.o e se no deixa
teste.o como esta.
all : o nome das regras a serem executadas.
teste: teste.c .Pode ser interpretado com arquivo_de_destino: arquivo_de_origem.
clean: Apaga os arquivos intermedirios.Se voc escrever no console make clean
ele apaga os arquivos objeto da pasta.
mrproper: Apaga tudo o que deve ser modificado.No console escreva make mrproper
Sintaxe de criao do arquivo
O makefile funciona de acordo com regras, a sintaxe de uma regra :
regra: dependncias
Apertar o boto TAB comando
comando ...
Regras complementares
all : o nome das regras a serem executadas.
clean: Apaga os arquivos intermedirios.
mrproper: Apaga tudo o que deve ser modificado.
Makefiles
154
Definir Variveis
As variveis servem para facilitar o trabalho.
Em vez de mudar varias linhas mudamos s o valor da varivel.
Deve ser por isso que se chama varivel, no?
Definimos da forma seguinte.
NOME=VALOR
E para utilizar esta varivel colocamos entre $() .
Ento ela vai ficar assim $(NOME)
Vamos para o exemplo com o nosso Makefile.
Colocamos em vez de :
NOME SRC
E em vez de VALOR main.c .
E para poder usar $(SRC)
Ser que na pratica funciona?. Vamos ver..
#Para escrever comentrios ##
############################# Makefile ##########################
#Definimos a varivel
SRC=main.c
all: teste
teste: teste.o main.o
gcc -o teste teste.o main.o
#-----> Distancia com o botao TAB ### e nao com espaos
teste.o: teste.c
gcc -o teste.o -c teste.c -W -Wall -ansi -pedantic
#
#Coloquei $(SRC) em todos os lugares aonde estava main.c
main.o: $(SRC) teste.h
gcc -o main.o -c $(SRC) -W -Wall -ansi -pedantic
clean:
rm -rf *.o
mrproper: clean
rm -rf teste
Todos os lugares do cdigo que contem o CONTEDO da varivel so modificados colocando no lugar respectivo o
NOME da
varivel.
Makefiles
155
Variveis Personalizadas
CC=gcc .Definimos CC para nomes de compiladores de C ou C++ .Aqui o gcc.
CFLAGS=-W -Wall -ansi -pedantic .Serve para definir opes passadas ao compilador.
Para o c++ o NOME e CXXFLAGS .
LDFLAGS e utilizado para editar as opes de links.
EXEC=teste .EXEC define o NOME do futuro programa executvel.
OBJ=teste.o main.o . Para cada arquivo.c um arquivo OBJETO e criado com a extenso ".o" arquivo.o .
Ento e s olhar na sua pasta todos os arquivos com a extenso ".c" e colocar na varivel OBJ com a extenso".o" .
Outra maneira e mesma coisa. OBJ agora e igual a main.o teste.o
SRC = main.c teste.c
OBJ= $(SRC:.c=.o)
E super manero a tua idia camarada.
Mais tenho 200 arquivos.c e no quero olhar o nome de todos um por um.
Tem outra idia??
Poderamos utilizar *c mais no podemos utilizar este caracter joker na definio de uma varivel.
Ento vamos utilizar o comando " wildcard " ele permite a utilizao de caracteres joker na definio de
variveis.
Fica assim.
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
Observao se quiser fazer aparecer uma mensagem durante a compilao escreva @echo "Minha mensagem" .
E mais tem um monte de mensagens e fica muito feio
Tem outra idia??.. O pessoal vamos parando ;) no sou uma maquina de idias.
Para deixar as mensagens em modo silencioso coloque "@" no comeo do comando.
Fica assim
@$(CC) -o $@ $^
Variveis internas
$@ Nome da regra.
$< Nome da primeira dependncia
$^ Lista de dependncias
$? Lista de dependncias mais recentes que a regra.
$* Nome do arquivo sem sufixo
Makefiles
156
As regras de interferncia
No disse nada antes porque estvamos no estado principiantes "noob".
So regras genricas chamadas por default.
.c.o : .Ela significa fazer um arquivo.o a partir de um arquivo.c .
%.o: %.c .A mesma coisa. A linha teste.o: teste.c pode ser modificada com essa regra.
.PHONY: .Preste bem ateno. Esta regra permite de evitar conflitos.
Por exemplo "clean:" e uma regra sem nem uma dependncia no temos nada na pasta que se chame clean.
Agora vamos colocar na pasta um arquivo chamado clean. Se voc tentar apagar os "arquivos.o" escrevendo
"make clean" no vai acontecer nada porque make diz que clean no foi modificado.
Para evitar esse problema usamos a regra .PHONY : . Fica assim.
.PHONY: clean mrproper
.PHONY: diz que clean e mrproper devem ser executados mesmo se arquivos com esses nomes existem.
Agora vamos modificar mais uma vez o nosso Makefile com tudo o que sabemos sobre variveis.
#Para escrever comentrios ##
############################# Makefile ##########################
#Definimos a varivel
CC=gcc
CFLAGS=-W -Wall -ansi -pedantic
EXEC=teste
OBJ=teste.o main.o
all: $(EXEC)
@echo "Vou comear a compilao"
#No coloquei a varivel OBJ para que possam entender as variveis internas.
#Se entenderam podem colocar $(OBJ) no lugar de teste.o main.o
teste: teste.o main.o
# $@ = teste:
# $^ = teste.o main.o
$(CC) -o $@ $^
# teste.o:teste.c
%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)
main.o: main.c teste.h
$(CC) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
rm -rf *.o
@echo "Compilaao prontinha"
mrproper: clean
rm -rf $(EXEC)
Po legal ;) parece at trabalho de gente grande.
Makefiles
157
Sub Makefiles
Ler tudo isso s para compilar um programa??
O sub-makefile e lanado por meio de um "Makefile principal" vamos simplificar para o Patro Makefile.
Aonde estvamos??...Ah sim, para que serve??
O Makefile Principal executa os sub-makesfiles de outras pastas.
Como ele faz??
Usamos uma varivel pre-definida $(MAKE).
Bao ao trabalho.. Crie dentro da pasta "Projetos" outra pasta com o nome "sub-make".Dentro da pasta sub-make crie
um arquivo
Makefile e um arquivo submake.c
Dentro da pasta sub-make coloque este Makefile.
##################Pasta:sub-make ## Makefile ###################
CC=gcc
CFLAGS=-W -Wall -ansi -pedantic
EXEC=teste2
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
all: $(EXEC)
@echo "compilando sub-makefile"
@echo "sub-makefile compilado"
teste2: $(OBJ)
@$(CC) -o $@ $^
.PHONY: clean mrproper
clean:
@rm -rf *.o
mrproper: clean
@rm -rf $(EXEC)
Agora vamos escrever o arquivo submake.c .
#include <stdio.h>
#include <stdlib.h>
/* Informao
* Nao utilizem este cdigo para fazer um kernel
*/
int main(void)
{
printf("Sou o binrio que est em sub-make");
printf("Finalmente em fim vivo graas ao Patro Makefiles ;)");
return (0);
}
Agora retorne na pasta "Projeto" vamos modificar o Makefile .
Vamos colocar a seguinte linha:
@cd sub-make && $(MAKE)
Explicando: "@" silencioso "cd" para abrir a pasta sub-make "&&" e executar make "$(MAKE)"
Makefiles
158
Vamos fazer a mesma coisa para "clean:" e "mrproper:" ento ao executar "make clean" no console ele vai
executar o mesmo comando no sub-makefile.
########################## O Makefile principal ##########################"
CC=gcc
CFLAGS=-W -Wall -ansi -pedantic
EXEC=teste
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
all: $(EXEC)
@echo "Compilando Projeto"
@echo "O patro foi compilado"
#A linha que vai compilar sub-make
@cd sub-make && $(MAKE)
teste: $(OBJ)
@$(CC) -o $@ $^
%.o: %.c
@$(CC) -o $@ -c $< $(CFLAGS)
main.o: main.c teste.h
@$(CC) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
@rm -rf *.o *~
# E a mesma coisa que dar um F4 dentro da pasta sub-make
# e escrever make clean
@cd sub-make && $(MAKE) $@
mrproper: clean
@rm -rf $(EXEC)
#modificamos aqui tambm
@cd sub-make && $(MAKE) $@
No esquea de dar TAB em todas as linhas que esto em baixo dos ":" dois pontinhos. OK agora s dar um F4
dentro da pasta projetos e voc tem trs comandos a disposio.
make
make clean
make mrproper
Make install
Automatizando a instalao do programa com a regra install: .
install: .Coloca o binrio ou executvel em uma determinada pasta, como por exemplo /bin ou /usr/bin no Linux.
Pode ser em qualquer outra, utilizando o comando "mv" ou "cp" para mover ou copiar.
Crie uma pasta bin dentro de "Projetos". Devem saber que no devem colocar nada intil que venha da internet na
pasta raiz do linux.
Vamos fazer duas variveis:
prefix=/caminho/ate onde/esta/Projetos
bindir=$(prefix)/bin .Igual a /caminho ate/Projetos/dentro de Projetos a pasta bin .
E adicionarmos a regra install:all com seus comandos.
Makefiles
159
Modificando o make principal.
########################## O Makefile principal ##########################"
#Coloque o caminho at Projeto aqui
prefix=/home/USER/Projeto
bindir=$(prefix)/bin
CC=gcc
CFLAGS=-W -Wall -ansi -pedantic
EXEC=teste
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
all: $(EXEC)
@echo "Compilando Projeto"
@echo "O patrao foi compilado"
#A linha que vai compilar sub-make
@cd sub-make && $(MAKE)
teste: $(OBJ)
@$(CC) -o $@ $^
%.o: %.c
@$(CC) -o $@ -c $< $(CFLAGS)
main.o: main.c teste.h
@$(CC) -o $@ -c $< $(CFLAGS)
#Entao depois e so executar make e depois make install
install:all
@mv $(EXEC) $(bindir)/
.PHONY: clean mrproper
clean:
@rm -rf *.o *~
# E a mesma coisa que dar um F4 dentro da pasta sub-make
# e escrever make clean
@cd sub-make && $(MAKE) $@
mrproper: clean
@cd bin && rm -rf $(EXEC)
#modificamos aqui tambem
@cd sub-make && $(MAKE) $@
Ento quando voc digitar no console "make" depois "make install" ele vai colocar o binario que esta em "Projetos"
dentro de "bin".
Se voc quiser colocar o binario que esta na pasta "sub-make" na pasta "bin"
Copiar e colar no makefile da "sub-make" as variaveis "prefix" e "bindir"e a regra install:com seu comando.
E no "Makefile principal" em baixo de "install:" coloque esta linha @cd sub-make && $(MAKE) $@
Aqui eu modifiquei o "mrproper" porque agora os binarios que devem ser apagados com "make mrproper" esto
em "bin".
Vou deixar voces modificarem o "mrproper" do "sub-makefile" como pessoas adultas e responsaveis ;) Valeu
galera.
Os comandos no console so:
make
Makefiles
160
make install
make clean
make mrproper .Para apagar os binarios.
Lista de palavras reservadas
A linguagem C possui um total de 32 palavras conforme definido pelo padro ANSI, que so elas:
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
importante lembrar que todas as palavras reservadas so escritas em minsculo e no podem ser utilizadas para
outro propsito. Alguns compiladores incluem outras palavras reservadas como, asm, cdecl, far, fortran,
huge, interrupt, near, pascal, typeof.
Seqncias de escape
O C tem vrias seqncias de escape. Elas servem geralmente para inserir um caractere especial numa String.
Algumas dessas seqncias so:
\a - Alarm, Alarme = Toca o alarme sonoro do sistema
\b - Back space, Retrocesso = Apaga o caractere esquerda do cursor
\n - NewLine, Nova linha = Pula uma linha
\t - Tabulao horizontal = Equivale dar um TAB na string
\r - Carriage Return, Retorno do Carro = Volta para o incio da linha.
\t - Horz. Tab, Tabulao Harizontal = Salta frente conforme seus ajustes de tabulao
\0 - Null, Nulo = Caractere nulo ou zero geralmente estabelecido como fim de string
Lista de funes
161
Lista de funes
Aqui esto as vrias funes presentes em C separadas por cabealho:
stdio.h
printf
scanf
vsnprintf
sprintf
vprintf
fprintf
fscanf
feof
fflush
calloc
malloc
system
gets
fgets
puts
fputs
stdlib.h
atoi
atof
atol
itoa
string.h
strcmp
stricmp
strlen
strstr
strcat
strcpy
strncpy
strncat
strchr
strrev
signal.h
iso10646.h
time.h
math.h
tan
sin
cos
atan
asin
acos
Lista de funes
162
pow
sqrt
abs
Lista de bibliotecas
Cabealhos de bibliotecas padro ANSI C (C89)/ISO C (C90):
assert.h
ctype.h
errno.h
float.h
limits.h
locale.h
math.h
setjmp.h
signal.h
stdarg.h
stddef.h
stdio.h
stdlib.h
string.h
time.h
Cabealhos adicionados no ISO C (C94/C95):
iso646.h wchar.h wctype.h
Cabealhos adicionados no ISO C (C99) (suportados somente em compiladores mais novos):
complex.h
fenv.h
inttypes.h
stdbool.h
stdint.h
tgmath.h
Ligaes externas
The Open Group Base Specifications Issue 7
[1]
(english)
Biblioteca C
[2]
(english)
Referncias
[1] http:/ / www. opengroup. org/ onlinepubs/ 9699919799/ functions/ contents. html
[2] http:/ / www. cplusplus. com/ reference/ clibrary/
Dicas de programao em C
163
Dicas de programao em C
Convenes tipogrficas
Uma das melhores maneiras de obter um cdigo claro e usando identificadores coerentes.
Por exemplo bom poder identificar rapidamente as variveis em funo de suas propriedades .
Veja abaixo algumas delas.
prefixos identificadores
- ponteiro p_
- tabela esttica(static array) a_ ou sa_
- tabela dinmica (dynamic array) da_
- cadeia de caracteres(string) s_
Em um cdigo com a varivel "p_exemplo" podemos deduzir rapidamente que estamos usando um ponteiro .
A funo printf a melhor amiga de um programador
Um programador novato tende a ver apenas duas aplicaes para o printf:
1. 1. Solicitar entrada para o usurio do programa.
2. 2. Imprimir o resultado do programa.
O fato que um programador pode aplicar o printf a fim de saber o que ocorre durante a execuo de programa. Isto
permite, dentre outras coisas, detectar erros.
Por exemplo, suponha um programa no qual vrias funes e rotinas so executadas. Algo como:
int main(int argc, char *argv[])
{
...
funcao1(...);
funcao2(...);
funcao3(...);
funcao4(...);
...
return 0;
}
Digamos que o programa tenha sido compilado com sucesso, mas ocorra algum erro durante sua execuo. Podemos
usar o printf para detectar o erro da seguinte maneira:
int main(int argc, char *argv[])
{
...
printf("iniciando funcao1");
funcao1(...);
printf("completa funo1, iniciando funcao2");
funcao2(...);
printf("completa funo2, iniciando funcao3");
funcao3(...);
printf("completa funo3, iniciando funcao4");
Dicas de programao em C
164
funcao4(...);
printf("completa funo4");
...
return 0;
}
Isto permite o programador determinar at que ponto o programa roda antes de dar erro, facilitando muito a deteco
deste.
Outro exemplo de como o printf til na deteco de problemas. Suponha um programa cheio de laos aninhados.
Tal como:
for(...)
{
while(...)
{
...
for(...)
{
...
}
}
}
Caso durante a execuo o programa entre em um loop infinito, uma forma de detectar em qual dos laos est o
problema :
for(...)
{ printf("Teste 1");
while(...)
{ printf("Teste 2");
...
for(...)
{ printf("Teste 3");
...
}
}
}
A impresso que se repetir eternamente aquela dentro do lao problemtico.
Um ltimo exemplo de deteco de problemas por meio do printf. Suponha que a resposta dada por um programa
no a esperada, que a resposta consiste na impresso de uma varivel x, a qual recebe diversas atribuies ao longo
do programa. Podemos identificar o erro dando um printf em x aps cada uma de suas atribuies:
x=...
printf("primeira atribuicao de x eh %tipo", x);
...
x=...
printf("segunda atribuicao de x eh %tipo", x);
...
x=...
Dicas de programao em C
165
printf("terceira atribuicao de x eh %tipo", x);
...
printf("A resposta eh %tipo", x);
Caso o valor de x dependa do valor de outras variveis que no so impressas, imprimi-las pode ajudar na deteco
do problema.
Para uso como debug, a linguagem C apresenta duas macros que quando utilizadas junto com o printf so timos
recursos.
__FILE__ = nome do arquivo.
__LINE__ = numero da linha de execuo.
O Compilador gcc ainda dispe de uma outra macro bastante util:
__PRETTY_FUNCTION__ = nome da funo atual.
...
printf("%d:%s:%s\n", __LINE__, __FILE__, __PRETTY_FUNCTION__);
...
O trecho acima vai te dar uma saida para debug muito util com o seguinte conteudo:
Exemplo:
3:hello.c:main
Tecle 1 para rodar
Existem duas formas de manter um programa rodando enquanto o usurio desejar:
1. 1. Conter a maior parte do programa dentro de um lao.
2. 2. Usar o comando goto(lembre-se que o comando goto no de uso aconselhado para a programao estruturada).
Alguns exemplos:
Com while:
int main(int argc, char *argv[])
{

int rodando=1;
while(rodando==1)/*Este laco mantem o programa rodando enquanto o
usuario desejar*/
{
...

printf("\nDigite 1 para continuar rodando o programa.");
printf("\nDigite qualquer outro numero para encerrar o programa. ");
scanf("%d", &rodando);
}

return 0;
}
Com do...while
Dicas de programao em C
166
int main(int argc, char *argv[])
{
short int rodando;
do /*Este laco mantem o programa rodando enquanto o usuario
desejar*/
{
...
printf("\nDigite 1 para manter o programa rodando. ");
scanf("%d", &rodando);
}while(rodando==1);

return 0;
}
Com o goto
int main(int argc, char *argv[])
{
MARCA:

...
FIM:
int y;
printf("Tecle 1 para continuar rodando o programa. Tecle 0 para
encerrar o programa\n");
scanf("%d",&y);
if(y==1)
{
goto MARCA;
}

if(y!=1 && y!=0)
{
goto FIM;
}
return 0;
}
Listas encadeadas
167
Listas encadeadas
Listas encadeadas so estruturas de dados lineares e dinmicas, a grande vantagem que elas possuem em relao ao
uso de vetor o fato de terem tamanho mximo relativamente infinito (o tamanho mximo o da memria do
computador), ao mesmo tempo que podem ter o tamanho mnimo de 1 elemento evitando o desperdcio de memria.
Primitivas
No existe nenhuma normalizao quanto as primitivas usadas para a manipulao de uma lista.
Abaixo voc pode ver uma lista com algumas delas .
Colocar o ndice sobre o primeiro elemento da lista.
Colocar o ndice sobre o ltimo elemento da lista .
Colocar o ndice sobre o elemento que segue o elemento atual .
Colocar o ndice sobre o elemento que precede o elemento atual .
Verificar se a lista est vazia : Se a lista estiver vazia retorna verdadeiro, se no, falso.
Verificar se o primeiro elemento : Retorna verdadeiro se o elemento atual o primeiro, se no, falso.
Verificar se o ltimo elemento : Retorna verdadeiro se o elemento atual o ltimo, se no, falso.
Verificar o nmero de elementos da lista : Retorna o nmero de elementos da lista.
Adicionar um elemento no incio : Adicionar um elemento antes do primeiro elemento da lista .
Adicionar um elemento no fim : Adicionar um elemento depois do ltimo elemento da lista .
Insero : Inserir um elemento antes do elemento atual .
Troca : Trocar o elemento atual .
Remoo : Remover o elemento atual .
Listar todos os elementos da lista .
Lista encadeada linear
Cada n ou elemento de uma lista encadeada ir possuir guardar o valor do n e o endereo do prximo n. Em uma
lista encadeada linear o ultimo elemento aponta para NULL .
struct No{
char *p_dados;
struct No *p_prox;
};
Iniciar uma lista
A funo abaixo demonstra como iniciar uma lista criando o espao da raiz na memria.
void criar_Lista(struct No **p_Raiz){
*p_Raiz = NULL;
}
Insero
Existem 3 tipos de insero em uma lista, pode-se inserir no comeo, no final ou entre dois elementos da lista.
Listas encadeadas
168
Insero no incio
int inserir_No_Inicio(struct No **p_Raiz, char *p_String){
struct No *p_Novo;
/** Alocao dinmica da memoria */
if((p_Novo = (struct No *) malloc(sizeof(struct No))) == NULL ){
puts( "Falta Memoria\n"); return -1 ;
}

p_Novo->p_dados = p_String;

p_Novo->p_prox = *p_Raiz;
*p_Raiz = p_Novo;
}
Insero no fim
int inserir_No_Fim(struct No **p_Raiz, char *p_String){
struct No *p_Novo;
if(( p_Novo = (struct No *) malloc(sizeof(struct No))) == NULL ){
puts( "Falta Memoria\n"); return -1 ;
}
p_Novo->p_dados = p_String;
p_Novo->p_prox = NULL;

if(*p_Raiz == NULL)
*p_Raiz = p_Novo;
else{
struct No *e_atual; /*@ Elemento atual*/
e_atual = *p_Raiz; /*@ Primeiro elemento*/

while(e_atual->p_prox != NULL){
e_atual = e_atual->p_prox;
}
e_atual->p_prox = p_Novo;
}
}
Remoo
Assim como na insero tambm existem 3 tipos de remoo, no incio, no fim ou entre dois elementos da lista.
Remoo no incio
void remover_No_Inicio(struct No **p_Raiz){
if(*p_Raiz == NULL) printf("\nA lista ja esta vazia\n");
else{
struct No *p_atual;
p_atual = *p_Raiz;

Listas encadeadas
169
*p_Raiz = (*p_Raiz)->p_prox;
free(p_atual);
}
}
Remoo no fim
void remover_No_Fim(struct No **p_Raiz){
if(*p_Raiz == NULL) printf("\nA lista ja esta vazia");
else{
struct No *p_atual, *p_anterior ;
p_atual = *p_Raiz;
while(p_atual->p_prox != NULL){
p_anterior = p_atual ;
p_atual = p_atual->p_prox;
}
p_anterior->p_prox = NULL;
free(p_atual);
}
}
Exibio
Do fim para a raiz
void mostrar_Do_Fim_Para_Raiz(struct No *p_Raiz){
if(p_Raiz == NULL) printf("\nLista vazia");
else{
struct No *p_Atual_Corredor, *p_Atual_Fim;
p_Atual_Corredor = p_Raiz;
p_Atual_Fim = p_Raiz;
while(p_Atual_Fim->p_prox != NULL){ //ir para o ultimo elemento
p_Atual_Fim = p_Atual_Fim->p_prox;
}
while(p_Atual_Corredor != p_Atual_Fim){
if(p_Atual_Corredor->p_prox == p_Atual_Fim){
printf(" <- %s", p_Atual_Fim->p_dados);
p_Atual_Fim = p_Atual_Corredor;
p_Atual_Corredor = p_Raiz;
}
else p_Atual_Corredor = p_Atual_Corredor->p_prox;
}
printf(" <- %s", p_Atual_Fim->p_dados);
}
}
Listas encadeadas
170
Da raiz para o fim
void mostrar_Da_Raiz_Para_Fim(struct No *p_Raiz){
if(p_Raiz == NULL) printf("\nLista vazia");
else{
struct No *p_atual;
p_atual = *p_Raiz;
while(p_atual != NULL){
printf("%s", p_atual->p_dados);
p_atual = p_atual->p_prox;

}
}
}
Pilha
Pilha
Pilha ou stack uma lista linear em que todas as inseres e remoes de elemento s podem ser feitos em uma
extremidade chamada topo.As pilhas tambm so chamadas de estruturas LIFO (Last In First Out) ou seja o ltimo
elemento inserido o primeiro removido.
Construo do prottipo de um elemento da lista.

typedef struct Elemento_da_lista{
char *dados;
struct Elemento_da_lista *proximo;
}Elemento;
struct Localizar{
Elemento *inicio;
int tamanho;
} Pilha;
Pilha
171
Inicializao
void iniciar (Localizar *monte){
monte->inicio = NULL;
monte->tamanho = 0;
}
Inserir um elemento na pilha(push)
Algoritmo:
Declarao do elemento(s) a ser inserido.
Alocao da memria para o novo elemento
Inicializar o campo de dados.
Preencher o ponteiro inicio com o primeiro elemento
Colocar em dia o tamanho da pilha.
int empilhar(Localizar * monte, char *dados){
Elemento *novo_elemento;
if ((novo_elemento = (Elemento *) malloc (sizeof (Elemento))) == NULL)
return -1;
if ((novo_elemento->dados = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (novo_elemento->dados, dados);
novo_elemento->proximo = monte->inicio;
monte->inicio = novo_elemento;
monte->tamanho++;
}
Retirar um elemento da pilha (pop)
int desempilhar (Localizar *monte){
Elemento *p_elemento;
if (monte->tamanho == 0)
return -1;
p_elemento = monte->inicio;
monte->inicio = monte->inicio->proximo;
free (p_elemento->dados);
free (p_elemento);
monte->tamanho--;
return 0;
}
Imprimir os elementos da pilha
void mostrar(Localizar * monte){
Elemento *atual;
int i;
atual = monte->inicio;
Pilha
172
for(i=0;i<monte->tamanho;++i){
printf("\t\t%s\n", atual->dados);
atual = atual->proximo;
}
}
Fila ou Queue
Fila
Uma fila ou queue em ingls uma estrutura de dados que usa o mtodo FIFO(acrnimo para First In, First Out, que
em portugus significa primeiro a entrar, primeiro a sair).
A idia fundamental da fila que s podemos inserir um novo elemento no final da fila e s podemos retirar o
elemento do incio.
Exemplo de fila em C:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void q_enter(void);
void q_list(void);
int q_store(char *ptr);
int q_delete(void);
int count = 0; //contador
int store = 0; // proxima posio na fila
int retrieve = 0; // recupera a posio da fila
char *queue[100]; // vetor da fila
int main()
{
int i = 0;
for ( i = 0; i < 100; i++ )
{
queue[i] = NULL;
}
q_enter(); // entra os dados na fila
printf("\n\nTodos os dados da fila (FIFO):\n");
q_list();
q_delete(); // Apaga a primeira entrada da fila
Fila ou Queue
173
printf("\n\nA fila depois delete(FIFO):\n");
q_list();
printf("\n\nNumero de elementos restantes na fila: %i \n", count);
getchar(); // espera
return 0;
}

void q_enter(void)
{
static char str[100], *ptr;
puts("Pressione a tecla ENTER sem nome pra sair\n");
do {
printf("Entre o nome:");
gets(str);
ptr = (char *) malloc(strlen(str)); //alocar um espao na memria
strcpy(ptr,str);
if (*str)
{
count++;
q_store(ptr); // Guarda o endereo da seqncia de caracteres
}
} while (*str); //Sair se no houver uma entrada
}


// listar a fila
void q_list(void)
{
int k;

for (k = retrieve; k < store; k++)
{
printf("Elemento %d : %s \n",k+1,queue[k]);
}
}

// Guarda os itens na fila
int q_store(char *ptr)
{
if (store == 100) {
printf("\nA lista esta cheia!\n");
return 0 ;
}
Fila ou Queue
174
queue[store] = ptr;
store++; // prximo ndice da fila
}

// Apaga um item da fila
int q_delete(void)
{
if (store == retrieve) {
printf("\nA fila esta vazia!");
return 0 ;
}
count--;
retrieve++;
}
rvores binrias
Este mdulo precisa ser revisado por algum que conhea o assunto (discuta).
Arvore binria
Uma arvore binria uma estrutura de dados que pode ser representada como uma hierarquia onde cada elemento
chamado de n. O n inicial ou o primeiro elemento chamado de raiz. Em uma rvore binria um elemento pode
ter um mximo de dois filhos no nvel inferior denominados como sub-rvore esquerda e sub-rvore direita.Um n
sem filhos chamado de folha. A profundidade de um n a distncia deste n at a raiz e a distancia entre a folha
mais distante e a raiz a altura da arvore.Um conjunto de ns com a mesma profundidade denominado, nvel da
rvore.
Struct
typedef struct No{
int numero;
struct No *esquerda;
struct No *direita;
}No;
rvores binrias
175
Iniciar
void criarArvore(No **pRaiz){
*pRaiz = NULL;
}
Insero
void inserir(No **pRaiz, int numero){
if(*pRaiz == NULL){
*pRaiz = (No *) malloc(sizeof(No));
(*pRaiz)->esquerda = NULL;
(*pRaiz)->direita = NULL;
(*pRaiz)->numero = numero;
}else{
if(numero < (*pRaiz)->numero)
inserir(&(*pRaiz)->esquerda, numero);
if(numero > (*pRaiz)->numero)
inserir(&(*pRaiz)->direita, numero);
}
}
Remoo
No *MaiorDireita(No **no){
if((*no)->direita != NULL)
return MaiorDireita(&(*no)->direita);
else{
No *aux = *no;
if((*no)->esquerda != NULL) // se nao houver essa verificacao,
esse n vai perder todos os seus filhos da esquerda!
*no = (*no)->esquerda;
else
*no = NULL;
return aux;
}
}
No *MenorEsquerda(No **no){
if((*no)->esquerda != NULL)
return MenorEsquerda(&(*no)->esquerda);
else{
No *aux = *no;
if((*no)->direita != NULL) // se nao houver essa verificacao,
esse n vai perder todos os seus filhos da direita!
*no = (*no)->direita;
else
*no = NULL;
return aux;
rvores binrias
176
}
}
void remover(No **pRaiz, int numero){
if(*pRaiz == NULL){ // esta verificacao serve para caso o numero
nao exista na arvore.
printf("Numero nao existe na arvore!");
getch();
return;
}
if(numero < (*pRaiz)->numero)
remover(&(*pRaiz)->esquerda, numero);
else
if(numero > (*pRaiz)->numero)
remover(&(*pRaiz)->direita, numero);
else{ // se nao eh menor nem maior, logo, eh o numero que
estou procurando! :)
No *pAux = *pRaiz; // quem programar no Embarcadero vai
ter que declarar o pAux no inicio do void! :[
if (((*pRaiz)->esquerda == NULL) && ((*pRaiz)->direita ==
NULL)){ // se nao houver filhos...
free(pAux);
(*pRaiz) = NULL;
}
else{ // so tem o filho da direita
if ((*pRaiz)->esquerda == NULL){
(*pRaiz) = (*pRaiz)->direita;
pAux->direita = NULL;
free(pAux); pAux = NULL;
}
else{ //so tem filho da esquerda
if ((*pRaiz)->direita == NULL){
(*pRaiz) = (*pRaiz)->esquerda;
pAux->esquerda = NULL
free(pAux); pAux = NULL;
}
else{ //Escolhi fazer o maior filho direito da
subarvore esquerda.
pAux = MaiorDireita(&(*pRaiz)->esquerda); //se vc
quiser usar o Menor da esquerda, so o que mudaria seria isso:
pAux->esquerda = (*pRaiz)->esquerda; //
pAux = MenorEsquerda(&(*pRaiz)->direita);
pAux->direita = (*pRaiz)->direita;
(*pRaiz)->esquerda = (*pRaiz)->direita = NULL;
free((*pRaiz)); *pRaiz = pAux; pAux = NULL;
}
}
rvores binrias
177
}
}
}
Em ordem
void exibirEmOrdem(No *pRaiz){
if(pRaiz != NULL){
exibirEmOrdem(pRaiz->esquerda);
printf("\n%i", pRaiz->numero);
exibirEmOrdem(pRaiz->direita);
}
}
Pr-ordem
void exibirPreOrdem(No *pRaiz){
if(pRaiz != NULL){
printf("\n%i", pRaiz->numero);
exibirPreOrdem(pRaiz->esquerda);
exibirPreOrdem(pRaiz->direita);
}
}
Ps-ordem
void exibirPosOrdem(No *pRaiz){
if(pRaiz != NULL){
exibirPosOrdem(pRaiz->esquerda);
exibirPosOrdem(pRaiz->direita);
printf("\n%i", pRaiz->numero);
}
}
Contar ns
int contarNos(No *pRaiz){
if(pRaiz == NULL)
return 0;
else
return 1 + contarNos(pRaiz->esquerda) +
contarNos(pRaiz->direita);
}
rvores binrias
178
Contar folhas
int contarFolhas(No *pRaiz){
if(pRaiz == NULL)
return 0;
if(pRaiz->esquerda == NULL && pRaiz->direita == NULL)
return 1;
return contarFolhas(pRaiz->esquerda) + contarFolhas(pRaiz->direita);
}
Altura da rvore
int maior(int a, int b){
if(a > b)
return a;
else
return b;
}
int altura(No *pRaiz){
if((pRaiz == NULL) || (pRaiz->esquerda == NULL && pRaiz->direita ==
NULL))
return 0;
else
return 1 + maior(altura(pRaiz->esquerda), altura(pRaiz->direita));
}
Algoritmos de ordenao
179
Algoritmos de ordenao
Insertion sort
void insertion_sort(int tabela[], int largura)
{
int i, memoria,
contador;
bool marcador;
for(i=1; i<largura; i++)
{
memoria = tabela[i];
contador = i-1;
do
{
marcador = false;

if(tabela[contador] > memoria)
{
tabela[contador+1] = tabela[contador];
contador--;
marcador = true;
}
if(contador < 0)
marcador = false;
}
while(marcador);
}
tabela[contador+1] = memoria;
Selection sort
void selectionSort( int vetorDesordenado[], int tamanhoVetor ) //Funao
selection recebendo vetor e tamanho
{
int i, j, posicaoValorMinimo;
for (i = 0; i < ( tamanhoVetor - 1 ); i++) //Loop para percorrer o vetor
{
posicaoValorMinimo = i; //O valor minimo de posiao do vetor a
ser percorrido e 0
for (j = ( i + 1 ); j < tamanhoVetor; j++)//Percorreremos o vetor da posiao 1 ate o tamanho estimado
{
if( vetorDesordenado[j] < vetorDesordenado[posicaoValorMinimo] ) //Se a posiao que vamos verificar for menos que a posiao que temos em maos
{
Algoritmos de ordenao
180
posicaoValorMinimo = j;//A variavel 'j' recebe esse valor
}
}

if ( i != posicaoValorMinimo )
{
trocarPosicaoValores( &vetorDesordenado[i],
&vetorDesordenado[posicaoValorMinimo] );//vamos chamar uma outra funao
para trocar as posioes de lugares
}
}
}
void trocarPosicaoValores( int *posicaoA, int *posicaoB )//Funao para
trocar as posioes que estamos olhando
{
int temporario;
temporario = *posicaoA;
*posicaoA = *posicaoB;
*posicaoB = temporario;
}
Bubble sort
O bubble sort, ou ordenao por flutuao (literalmente "por bolha"), um algoritmo de ordenao dos mais
simples. A ideia percorrer o vetor diversas vezes, a cada passagem fazendo flutuar para o topo o maior elemento da
sequncia. Essa movimentao lembra a forma como as bolhas em um tanque de gua procuram seu prprio nvel, e
disso vem o nome do algoritmo.
No melhor caso, o algoritmo executa operaes relevantes, onde n representa o nmero de elementos do vetor.
No pior caso, so feitas operaes. A complexidade desse algoritmo de Ordem quadrtica. Por isso, ele no
recomendado para programas que precisem de velocidade e operem com quantidade elevada de dados.
Cdigo da Funo
void BubbleSort(int vetor[], int tamanho)
{
int aux, i, j;

for(j=tamanho-1; j>=1; j--)
{
for(i=0; i<j; i++)
{
if(vetor[i]>vetor[i+1])
{
aux=vetor[i];
vetor[i]=vetor[i+1];
vetor[i+1]=aux;
}
Algoritmos de ordenao
181
}
}
}
Cdigo da Funo Melhorado
Termina a execuo quando nenhuma troca realizada aps uma passada pelo vetor.
void BubbleSort(int vetor[], int tamanho)
{
int memoria, troca, i, j;

troca=1; /*A varivel "troca" ser a verificao da troca em cada
passada*/

for(j=tamanho-1; (j>=1) && (troca==1); j--)
{
troca=0; /*Se o valor continuar 0 na prxima passada quer
dizer que no houve troca e a funo encerrada.*/

for(i=0; i<j; i++)
{
if(vetor[i]>vetor[i+1])
{
memoria=vetor[i];
vetor[i]=vetor[i+1];
vetor[i+1]=memoria;
troca=1; /*Se houve troca, "troca"
recebe 1 para continuar rodando.*/
}
}
}
}
Algoritmo de alocao
182
Algoritmo de alocao
best fit
Varre toda a memria e escolhe a pgina mais ajustada ao tamanho do processo.
#include <stdio.h>
#include <windows.h>

int main(){
int p,m;
printf("Entre o numero de processos:");
scanf("%d",&p);
printf("Entre o numero de blocos de memoria:");
scanf("%d",&m);

int parr[p];
struct memoria{
int id; // identificador
int tamanho;
}marr[m];

int i;

for(i=0;i<p;i++)
{
printf("Entre o tamanho do processo %d:",i+1);
scanf("%d",&parr[i]);
}
for(i=0;i<m;i++)
{
printf("Entre o tamanho do bloco de memoria %d:",i+1);
scanf("%d",&marr[i].tamanho);
marr[i].id=i+1;
}
int j;
int tamanho = 0;

for(i; tamanho <= marr[i].tamanho; i++ )
tamanho = marr[i].tamanho;
int tamanho_velho = tamanho ;
int im ;
bool marcador = false ;

for(i=0;i<p;i++){
for(j=0;j<m;j++){
if((marr[j].tamanho>=parr[i]) && (marr[j].tamanho < tamanho) ){
Algoritmo de alocao
183

im = j;
tamanho = marr[j].tamanho;
marcador = true ;

}

}

if(marcador){
marcador = false ;
marr[im].tamanho-=parr[i];
tamanho = tamanho_velho ;
printf("\n\nAloca o processo %d no bloco memoria %d\n
Tamanho restante apos alocar %d\n",i+1,marr[im].id,marr[im].tamanho);

}else {printf("Memoria insuficiente para o processo
%d",i);break;}


}
system ("pause");

return 0;
}
worst fit
O algoritmo worst fit aloca o bloco de memria na regio que tem o maior espao livre.
Est tcnica por procurar ocupar primeiro as parties maiores termina por deixar espaos livres que poderiam ser
utilizados para que outros blocos de outros programas as utilizassem, diminuindo e/ou retardando a fragmentao.
Buddy System
Esta pgina um esboo de informtica. Ampliando-a voc ajudar a melhorar o Wikilivros.
Lista de autores
184
Lista de autores
Lista de autores
Edudobay - Eduardo Sangiorgio Dobay
EvertonS - Everton.S.Baron
Lightningspirit
ThiagoL
Uder
Wbrito
RenatoResende
Maxtremus
Noturno99 - Bruno Sampaio Pinho da Silva
Fontes e Editores da Pgina
185
Fontes e Editores da Pgina
Capa Fonte: http://pt.wikibooks.org/w/index.php?oldid=186016 Contribuidores: David Stress, Delemon, Edudobay, Elvire, Joaodaveiro, Jorge Morais, Lightningspirit, Master, SallesNeto BR,
Voz da Verdade, Wbrito, 159 edies annimas
Por que aprender a linguagem C Fonte: http://pt.wikibooks.org/w/index.php?oldid=268284 Contribuidores: Abacaxi, Edudobay, Fabiobasso, Jorge Morais, Joo Jernimo, Lightningspirit,
SallesNeto BR, Sourf, Thiagol, Wbrito, 11 edies annimas
Histria da linguagem C Fonte: http://pt.wikibooks.org/w/index.php?oldid=266800 Contribuidores: Abacaxi, Edudobay, Helder.wiki, Jorge Morais, Lightningspirit, Scorpion, 14 edies
annimas
Pr-requisitos Fonte: http://pt.wikibooks.org/w/index.php?oldid=260172 Contribuidores: Abacaxi, Albmont, Edudobay, Helder.wiki, Jorge Morais, Lightningspirit, Marcos Antnio Nunes de
Moura, Wbrito, 17 edies annimas
Utilizando um compilador Fonte: http://pt.wikibooks.org/w/index.php?oldid=263662 Contribuidores: Abacaxi, Albmont, Edudobay, EvertonS, Fabiobasso, Master, Thiagol, Wesley
Ferdinando R. Carvalho, 7 edies annimas
Noes de compilao Fonte: http://pt.wikibooks.org/w/index.php?oldid=212773 Contribuidores: Aprendiz de feiticeiro, Edudobay, SallesNeto BR, Thiagol, Wbrito
Um programa em C Fonte: http://pt.wikibooks.org/w/index.php?oldid=263594 Contribuidores: Awillian, Edudobay, EvertonS, Fabiobasso, Jorge Morais, Marcos Antnio Nunes de Moura,
Thiagol, Wbrito, 12 edies annimas
Conceitos bsicos Fonte: http://pt.wikibooks.org/w/index.php?oldid=246560 Contribuidores: Algum, Edudobay, Fabiobasso, Helder.wiki, Thiagol, Wbrito, 3 edies annimas
Variveis Fonte: http://pt.wikibooks.org/w/index.php?oldid=266502 Contribuidores: Abacaxi, Defender, Edudobay, EvertonS, Helder.wiki, Jorge Morais, Marcos Antnio Nunes de Moura,
Mr.Yahoo!, Thiagol, Wbrito, 17 edies annimas
Tipos de dados Fonte: http://pt.wikibooks.org/w/index.php?oldid=270380 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Master,
PODEROS ARAN, Raylton P. Sousa, Wbrito, 16 edies annimas
Constantes Fonte: http://pt.wikibooks.org/w/index.php?oldid=256737 Contribuidores: Abacaxi, Daveiro, Helder.wiki, Iraziel, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura,
Master, SallesNeto BR, Wbrito, 8 edies annimas
Entrada e sada simples Fonte: http://pt.wikibooks.org/w/index.php?oldid=263547 Contribuidores: Abacaxi, Albmont, Edudobay, EvertonS, Thiagol, Wbrito, Yuu eo, 20 edies annimas
Operaes matemticas (Bsico) Fonte: http://pt.wikibooks.org/w/index.php?oldid=248640 Contribuidores: Edudobay, Wbrito, 4 edies annimas
Operaes matemticas (Avanado) Fonte: http://pt.wikibooks.org/w/index.php?oldid=270610 Contribuidores: Marcos Antnio Nunes de Moura, Rogerboff, SallesNeto BR, Thiagol, Wbrito,
9 edies annimas
Operadores Fonte: http://pt.wikibooks.org/w/index.php?oldid=248481 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Master, Petrusz1,
Raylton P. Sousa, Wbrito, 13 edies annimas
Controle de fluxo Fonte: http://pt.wikibooks.org/w/index.php?oldid=267376 Contribuidores: Abacaxi, Albmont, Edudobay, Helder.wiki, Hycesar, Rogerboff, Thiagol, Wbrito, 8 edies
annimas
Funes Fonte: http://pt.wikibooks.org/w/index.php?oldid=266990 Contribuidores: Abacaxi, Albmont, Awillian, Cleiton wi, Edudobay, EvertonS, Fabiobasso, Hycesar, Marcos Antnio Nunes
de Moura, Rogerboff, Victor Aurlio, Wbrito, 60 edies annimas
Pr-processador Fonte: http://pt.wikibooks.org/w/index.php?oldid=266815 Contribuidores: Abacaxi, Edudobay, EvertonS, Hycesar, Lgrave, Rogerboff, SallesNeto BR, 2 edies annimas
Exerccios Fonte: http://pt.wikibooks.org/w/index.php?oldid=268678 Contribuidores: Abacaxi, Albmont, Algum, Delemon, Jorge Morais, Lightningspirit, Raylton P. Sousa, Wbrito, 9 edies
annimas
Vetores Fonte: http://pt.wikibooks.org/w/index.php?oldid=270077 Contribuidores: Abacaxi, Ajraddatz, Dante Cardoso Pinto de Almeida, Edudobay, EvertonS, Fabiobasso, Helder.wiki,
Hycesar, Jonas AGX, Wbrito, 20 edies annimas
Strings Fonte: http://pt.wikibooks.org/w/index.php?oldid=266720 Contribuidores: Abacaxi, Albmont, Defender, Edudobay, Jorge Morais, Stryn, Wbrito, 18 edies annimas
Passagem de parmetros Fonte: http://pt.wikibooks.org/w/index.php?oldid=245335 Contribuidores: Abacaxi, David Stress, EvertonS, Wbrito, 4 edies annimas
Tipos de dados definidos pelo usurio Fonte: http://pt.wikibooks.org/w/index.php?oldid=234520 Contribuidores: Edudobay, Wbrito, 11 edies annimas
Enumerao Fonte: http://pt.wikibooks.org/w/index.php?oldid=255616 Contribuidores: Abacaxi, Daveiro, EvertonS, Helder.wiki, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de
Moura, Master, Wbrito, 18 edies annimas
Unio Fonte: http://pt.wikibooks.org/w/index.php?oldid=255617 Contribuidores: Abacaxi, Daveiro, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura, Master, Wbrito, 5 edies
annimas
Estruturas Fonte: http://pt.wikibooks.org/w/index.php?oldid=270091 Contribuidores: Abacaxi, Albmont, Daveiro, EvertonS, Jorge Morais, Marcelo-Silva, Marcos Antnio Nunes de Moura,
Master, Wbrito, 25 edies annimas
Ponteiros Fonte: http://pt.wikibooks.org/w/index.php?oldid=268629 Contribuidores: Abacaxi, Albmont, C++NERD, Edudobay, EvertonS, Fabiobasso, Hycesar, Jesielt, Jorge Morais, Jnior D.
Eskelsen,, Marcos Antnio Nunes de Moura, Noturno99, Wbrito, 29 edies annimas
Mais sobre variveis Fonte: http://pt.wikibooks.org/w/index.php?oldid=266141 Contribuidores: Abacaxi, Edudobay, GabrielFalcao, Helder.wiki, Wbrito, 3 edies annimas
Mais sobre funes Fonte: http://pt.wikibooks.org/w/index.php?oldid=250214 Contribuidores: Abacaxi, EvertonS
Bibliotecas Fonte: http://pt.wikibooks.org/w/index.php?oldid=265808 Contribuidores: Edudobay, EvertonS, Helder.wiki, Rogerboff, Torneira, Wbrito, 5 edies annimas
Entrada e sada em arquivos Fonte: http://pt.wikibooks.org/w/index.php?oldid=266993 Contribuidores: Abacaxi, Edudobay, EvertonS, MateusGPe, Wbrito, 4 edies annimas
Gerenciamento de memria Fonte: http://pt.wikibooks.org/w/index.php?oldid=266464 Contribuidores: Abacaxi, Edudobay, Frigotoni, Gabrielhtec, Marcos Antnio Nunes de Moura, 21
edies annimas
Sockets Fonte: http://pt.wikibooks.org/w/index.php?oldid=253321 Contribuidores: Abacaxi, Albmont, EvertonS, Jorge Morais, 8 edies annimas
Makefiles Fonte: http://pt.wikibooks.org/w/index.php?oldid=269628 Contribuidores: David Stress, EvertonS, Helder.wiki, Jorge Morais, 52 edies annimas
Lista de palavras reservadas Fonte: http://pt.wikibooks.org/w/index.php?oldid=186025 Contribuidores: Jorge Morais, 2 edies annimas
Seqncias de escape Fonte: http://pt.wikibooks.org/w/index.php?oldid=186035 Contribuidores: Devarde, Master, SallesNeto BR, 3 edies annimas
Lista de funes Fonte: http://pt.wikibooks.org/w/index.php?oldid=186024 Contribuidores: Devarde, Master, SallesNeto BR
Fontes e Editores da Pgina
186
Lista de bibliotecas Fonte: http://pt.wikibooks.org/w/index.php?oldid=254253 Contribuidores: Abacaxi, EvertonS, Jorge Morais, Marcos Antnio Nunes de Moura, 3 edies annimas
Dicas de programao em C Fonte: http://pt.wikibooks.org/w/index.php?oldid=258291 Contribuidores: Abacaxi, Dante Cardoso Pinto de Almeida, Helder.wiki, 8 edies annimas
Listas encadeadas Fonte: http://pt.wikibooks.org/w/index.php?oldid=263996 Contribuidores: Abacaxi, EvertonS, Gabrielhtec, Jorge Morais, Maxtremus, 15 edies annimas
Pilha Fonte: http://pt.wikibooks.org/w/index.php?oldid=269386 Contribuidores: Lukas, 11 edies annimas
Fila ou Queue Fonte: http://pt.wikibooks.org/w/index.php?oldid=243774 Contribuidores: Abacaxi, Defender, 6 edies annimas
rvores binrias Fonte: http://pt.wikibooks.org/w/index.php?oldid=270888 Contribuidores: Abacaxi, Aldnonymous, EvertonS, Marcos Antnio Nunes de Moura, Maxtremus, Ruy Pugliesi, 53
edies annimas
Algoritmos de ordenao Fonte: http://pt.wikibooks.org/w/index.php?oldid=254603 Contribuidores: Abacaxi, EvertonS, 12 edies annimas
Algoritmo de alocao Fonte: http://pt.wikibooks.org/w/index.php?oldid=270419 Contribuidores: EvertonS, Jorge Morais, Torneira, 9 edies annimas
Lista de autores Fonte: http://pt.wikibooks.org/w/index.php?oldid=249033 Contribuidores: Cardinhotk, EvertonS, RenatoResende, 3 edies annimas
Fontes, Licenas e Editores da Imagem
187
Fontes, Licenas e Editores da Imagem
Imagem:Programar_c_cover.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Programar_c_cover.png Licena: GNU Free Documentation License Contribuidores: Dante
Cardoso Pinto de Almeida, Lightningspirit
Image:Recycle001.svg Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Recycle001.svg Licena: desconhecido Contribuidores: Users Cbuckley, Jpowell on en.wikipedia
Image:Ken n dennis.jpg Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Ken_n_dennis.jpg Licena: Public Domain Contribuidores: 32X, Bastique, DenisKrivosheev, Ebcdic, Lzur,
Mormegil, Quibik, Reisio, Skim, Sven, 1 edies annimas
Imagem:Searchtool.svg Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Searchtool.svg Licena: GNU Lesser General Public License Contribuidores: David Vignoni, Ysangkok
Image:Nuvola apps konsole.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Nuvola_apps_konsole.png Licena: GNU Lesser General Public License Contribuidores: Alno,
Alphax
imagem:Exercicios c cover.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Exercicios_c_cover.png Licena: GNU Free Documentation License Contribuidores: Dante Cardoso
Pinto de Almeida, Lightningspirit
Image:Merge-arrows.svg Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Merge-arrows.svg Licena: Public Domain Contribuidores: User:Erin Silversmith, User:Lifeisunfair,
User:Rei-artur
Imagem:EsquemaPonteiro.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:EsquemaPonteiro.png Licena: desconhecido Contribuidores: Edudobay
Imagem:Crystal_Clear_app_kaddressbook.png Fonte: http://pt.wikibooks.org/w/index.php?title=Ficheiro:Crystal_Clear_app_kaddressbook.png Licena: GNU Free Documentation License
Contribuidores: CyberSkull, It Is Me Here, Rocket000
Licena
188
Licena
Creative Commons Attribution-Share Alike 3.0
//creativecommons.org/licenses/by-sa/3.0/

You might also like