Você está na página 1de 83

UFU Universidade Federal de Uberlndia

Faculdade de Computao





Apostila de Linguagem C
(Conceitos Bsicos)





Prof. Luiz Gustavo Almeida Martins
UFU Universidade Federal de Uberlndia Faculdade de Computao
LINGUAGEM C Conceitos Bsicos
1. INTRODUO
1.1. HISTRICO
A Linguagem C, criada em 1970 por Dennis Ritchie, uma evoluo da Linguagem B que, por sua
vez, foi uma adaptao feita, a partir da Linguagem BCPL, por Ken Thompson. Ela
estreitamente associada ao sistema operacional UNIX, j que as verses atuais do prprio
sistema foram desenvolvidas utilizando-se esta linguagem.
Devido ao crescente uso e interesse da comunidade de computao pela linguagem, em 1983, o
American National Standards Institute (ANSI), estabeleceu um comit para prover uma definio
moderna e abrangente da linguagem C. O resultado desta comisso foi uma padronizao
denominada ANSI-C em 1988. A maior contribuio deste trabalho foi a incorporao de uma
biblioteca padro, presentes em todas as variaes/verses da linguagem, que fornece funes
de acesso ao sistema operacional, entrada e sada formatada, alocao de memria, manipulao
de strings (cadeias de caracteres), etc.
1.2. CONCEITOS BSICOS
A filosofia bsica da linguagem C que os programadores devem estar cientes do que esto
fazendo, ou seja, supe-se que eles saibam o que esto mandando o computador fazer, e
explicitem completamente as suas instrues. Assim, ela alia a elegncia e a flexibilidade das
linguagens de alto nvel (ex: suporte ao conceito de tipo de dados) com o poderio das
linguagens de baixo nvel (ex: manipulao de bits, bytes e endereos).
O C uma linguagem de programao de finalidade geral, utilizada no desenvolvimento de
diversos tipos de aplicao, como processadores de texto, sistemas operacionais, sistemas de
comunicao, programas para soluo de problemas de engenharia, fsica, qumica e outras
cincias, etc.
O cdigo-fonte de um programa C pode ser escrito em qualquer editor de texto que seja capaz
de gerar arquivos em cdigo ASCII (sem formatao). Como o ambiente de programao
utilizado (Turbo C) para o sistema operacional DOS, estes arquivos devem ter um nome de no
mximo 8 caracteres e a extenso c (exemplo: NONAME.C).
Aps a implementao, o programa-fonte (um ou mais arquivos-fonte) submetido aos
processos de compilao e linkedio para gerar o programa executvel (com extenso exe).
Durante o processo de compilao, cada arquivo-fonte compilado separadamente,
produzindo um arquivo de cdigo-objeto com a extenso obj. Estes arquivos-objeto contm
instrues em linguagem de mquina (cdigos binrios) entendidas somente pelos
microprocessadores. Na linkedio, todos os arquivos-objetos pertencentes ao projeto, bem
como as bibliotecas declaradas nos cdigos-fonte so processadas em conjunto, visando a
produo do arquivo executvel correspondente.
Normalmente, tanto o arquivo-objeto quanto o arquivo executvel possuem o mesmo nome do
arquivo-fonte. Entretanto, quando desejado, o usurio poder definir diferentes nomes para cada
tipo de arquivo.
1.3. CARACTERSTICAS GERAIS
Prof. Luiz Gustavo Almeida Martins Pg.: 1/82
A linguagem C possui as seguintes caractersticas:
UFU Universidade Federal de Uberlndia Faculdade de Computao
Alta portabilidade inerente da padronizao ANSI, ou seja, possvel tomar um cdigo-
fonte escrito para uma mquina, compil-lo e rod-lo em outra com pouca ou nenhuma
alterao;
Gera programas formados basicamente por funes, o que facilita a modularizao e
a passagem de parmetros entre os mdulos;
Inicia a execuo a partir da funo main(), necessria em todos os programas;
Uso de chaves ({ }) para agrupar comandos pertencentes a uma estrutura lgica (ex: if-
else, do-while, for, etc.) ou a uma funo;
Uso do ponto e vrgula (;) ao final de cada comando;
case sensitive, ou seja, o compilador difere maisculas de minsculas. Assim, se
declarar uma varivel de nome idade, esta ser diferente de Idade, IDADE, etc. Alm
disso, todos os comandos da linguagem devem ser escritos em minsculo.
1.4. ESTRUTURA BSICA DE UM PROGRAMA C
Diretivas
Declaraes de variveis/constantes globais;
Prototipao de funes;
tipo_dado main(lista_parametros) /* Funo Principal e Obrigatria */
{
Declaraes de variveis/constantes locais;
Comandos;
Estruturas de controle (seleo e/ou repetio);
Comentrios;
Chamada a outras funes;
}
tipo_dado func1(lista_parametros)
{
Bloco de comandos;
}
tipo_dado func2(lista_parametros)
{
Bloco de comandos;
}



tipo_dado funcN(lista_parametros)
{
Bloco de comandos;
Prof. Luiz Gustavo Almeida Martins Pg.: 2/82
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
1.5. COMENTRIOS
Em C, comentrios podem ser escritos em qualquer lugar do texto para facilitar a interpretao do
algoritmo. Para que o comentrio seja identificado como tal, ele deve ter um /* antes e um */
depois.
Vale lembrar que, durante a compilao do programa, os comentrios so descartados pelo
compilador.
Exemplo:
/* esta e uma linha de comentrio em C */
2. DIRETIVAS
Durante a confeco do cdigo-fonte, alm dos comandos normais, o programador poder utilizar-
se de diretivas de compilao. As diretivas so prontamente reconhecidas, vista que aparecem
quase sempre no incio dos arquivos-fonte, com o prefixo # seguido pelo nome da diretiva e
seus argumentos. Ao contrrio dos comandos normais, no se usa ponto e vrgula ao final da
declarao da diretiva. Elas direcionam o compilador entre vrios caminhos durante a fase de
ET
pr-processamento.
Um importante exemplo a diretiva INCLUDE, a qual permite incorporar, no arquivo-fonte, o

Cdigo-
Fonte (.C)
APAS DO PROCESSO DE COMPILAO/LINKEDIO
contedo de outro arquivo passado como argumento. Ela propicia a utilizao de arquivos de
incluso criados pelo usurio ou fornecidos junto com o compilador (normalmente arquivos de
cabealho com extenso h). Os arquivos criados pelos usurios visam a reutilizao de funes
de uso geral j desenvolvidas, de modo a evitar digitaes repetitivas. J os arquivos fornecidos
pelo fabricante do compilador visam suprir as definies e declaraes mais frequentemente
necessrias, de acordo com a norma ANSI-C, possibilitando, assim, a portabilidade do cdigo-
fonte. As principais formas de indicar a localizao do arquivo de incluso so:
Pr-Processamento
da Linkedio
Linkedio
Cdigo-Fonte +
Arqs. de Incluso
Cdigo-Objeto (.OBJ)
Conjunto de Cdigos-Objeto + Bibliotecas
Programa-Executvel (.EXE)
Pr-Processamento
da Compilao
Compilao
Prof. Luiz Gustavo Almeida Martins Pg.: 3/82
UFU Universidade Federal de Uberlndia Faculdade de Computao
#include <stdio.h> Busca o arquivo stdio.h primeiramente no diretrio de incluso
(padro: C:\TC\INCLUDE)
#include stdio.h Busca o arquivo stdio.h primeiramente no diretrio de trabalho.
Independentemente da forma utilizada, este comando ordena ao pr-processador que carregue o
contedo do arquivo stdio.h como parte integrante do arquivo-fonte, exatamente naquele ponto.
Tal ao no afeta fisicamente o arquivo-fonte.
Os arquivos de incluso podem ser agrupados, isto , um arquivo de incluso pode conter outros
arquivos de incluso adicionais, e assim por diante, at o limite de pelo menos 8 nveis, conforme
determinao do padro ANSI (no Turbo C pode haver at 16 nveis de incluses aninhadas).
Na tabela abaixo so apresentados alguns arquivos de incluso que podem ser utilizados na
confeco dos programas.
ARQUIVOS DE CABEALHO PADRO ANSI C
ARQUIVO FINALIDADE
assert.h Contm a macro assert que usada para incluir diagnstico em programas
ctype.h Declara funes para testar caracteres
errno.h Define o nmero de erro do sistema
float.h Define os valores em ponto flutuante especficos do compilador
limits.h Define tipos de valores-limites especficos do compilador
locale.h Utilizada para adaptar as diferentes convenes culturais
math.h Define as funes matemticas e macros usadas para operaes matemticas em
linguagem C
setjmp.h Prov uma forma de evitar a seqncia normal de chamada e retorno de funo
profundamente aninhada
signal.h Prov facilidades para manipular condies excepcionais que surgem durante a
execuo, como um sinal de interrupo de uma fonte externa ou um uso na
execuo
stdarg.h Define macros para acessar argumentos quando uma funo usa um nmero
varivel de argumentos
stddef.h Define funes, constantes, macros e estruturas usadas para operaes padres
de entrada e sada
stdio.h Contm funes, tipos e macros de entrada e sada
stdlib.h Contm funes para converso de nmeros, alocao de memria e tarefas
similares
string.h Define funes para manipulao de strings
time.h Define funes e estruturas usadas na manipulao de data e hora.
Outra diretiva que tambm muito utilizada a DEFINE. Ela o mecanismo bsico do C para criar
macros e identificadores. A diretiva DEFINE precedida do smbolo # e seguida de dois
argumentos, de acordo com a finalidade desejada.
Na criao de um identificador, o primeiro argumento indica o nome do identificador e o segundo
define o contedo que ser associado a este identificador, como no exemplo abaixo:
#define NOME Fulano de Tal
Prof. Luiz Gustavo Almeida Martins Pg.: 4/82
Neste caso, o pr-processador da compilao substituir toda a apario subseqente do
identificador NOME, em qualquer lugar do cdigo-fonte, pela string Fulano de Tal. Vale ressaltar
que, se o pr-processador encontrar a palavra NOME dentro de uma string, isto , entre aspas
(ex: Digite o seu NOME), no ser realizada nenhuma substituio.
UFU Universidade Federal de Uberlndia Faculdade de Computao
Quando a string muito longa para ocupar uma nica linha, pode-se empregar o caracter especial
de escape (barra invertida - \) antes do <ENTER> e continuar digitando o texto restante na
prxima linha, como a seguir:
# define AVISO Este texto muito grande, \
assim estou utilizando a barra invertida para mant-lo dentro da minha tela
No existe nenhuma regra de substituio de strings. Assim, qualquer seqncia de caracteres
ser literalmente e exatamente inserida no cdigo-fonte, onde quer que o identificador
correspondente seja encontrado. A nica exceo o macete de continuao de linha, j que a
barra invertida no parte integrante da string. A verificao sinttica (sentido contextual) da
substituio ser realizada posteriormente durante a fase de compilao propriamente dita.
Na criao de macros, a diretiva DEFINE funciona de modo similar a uma funo, exceto pelo fato
de que, como macro, ela permite que argumentos sejam suprimidos, ao contrrio das funes. O
primeiro argumento da diretiva indica o nome da macro e os argumentos que sero utilizados
por ela. J o segundo argumento define como os argumentos da macro sero aplicados
quando o pr-processador encontrar o nome da macro no cdigo-fonte restante. Abaixo
apresentado um exemplo de macro:
#define CUBO(X) ((X)*(X)*(X))
Neste exemplo, o pr-processador substituir o texto CUBO(X) pelo valor correspondente a X
3
,
como nos exemplos abaixo:
CUBO(2) ((2)*(2)*(2)) =8
CUBO(A+B) ((A+B)*(A+B)*(A+B))
Neste ltimo caso, possvel notar a importncia dos parnteses em torno X na definio da ao
na declarao do DEFINE. Sem eles, a substituio de CUBO(A+B) seria equivocada, visto que o
resultado seria (A+B*A+B*A+B) e a multiplicao tem precedncia sobre a soma.
O ANSI-C fornece dois operadores do pr-processador para serem utilizados em macros definidas
pelo DEFINE. So eles:
# transforma o argumento que ele precede em uma string entre aspas
Ex: #define mkstr(s) # s
printf(mkstr(Processamento de Dados));
## concatena duas palavras
Ex: #define concat(a,b) a ## b
printf(concat( Processamento , de Dados );
Em ambos os casos, o resultado gerado equivalente ao comando:
printf( Processamento de Dados );
Prof. Luiz Gustavo Almeida Martins Pg.: 5/82
Apesar de existirem outras diretivas de compilao, inclusive algumas que permitem compilao
condicional, essas fogem ao escopo do curso e, portanto, no sero discutidas neste material.
UFU Universidade Federal de Uberlndia Faculdade de Computao
3. PROTTIPOS DE FUNES
O padro ANSI C expandiu a declarao tradicional de funo, permitindo que a quantidade e os
tipos dos argumentos das funes sejam declarados no incio do programa. Esta definio
expandida chamada de prottipo da funo.
Prottipos permitem que o C fornea uma verificao mais forte de tipos, ou seja, atravs dos
prottipos, o C pode encontrar e apresentar quaisquer converses ilegais de tipo entre o
argumento usado para chamar a funo (argumento atual) e aquele utilizado na definio de seus
parmetros (argumento formal). Alm disso, o uso de prottipo tambm permite encontrar
diferenas entre o nmero destes argumentos. Portanto, a sua utilizao ajuda na deteco de
erros antes que eles ocorram.
A forma geral de uma definio de prottipo de funo :
tipo nm_funo (tipo nm_arg1, tipo nm_arg2, ... , tipo nm_argN);
Exemplo:
# include <stdio.h>
unsigned int NUM;
int fat (unsigned int NRO); /* Prottipo da Funo fat() */
void main (void)
{
scanf(%u, &NUM);
printf(\nO fatorial de %u %d, NUM, fat(NUM));
}
Int fat(unsigned int NRO)
{
if NRO < 2
return (1);
else
return (NRO * fat(NRO-1));
}
O uso dos nomes dos parmetros opcional. Porm, eles habilitam o compilador a identificar
qualquer incompatibilidade de tipo atravs do nome quando ocorre um erro.
Devido necessidade de compatibilidade com a verso original do C, a qual no possui prottipo
de funes, algumas informaes adicionais devem ser consideradas:
Quando uma funo no possui argumentos, seu prottipo deve usar void dentro dos
parnteses (ex: int func (void);). Isso infroma ao compilador que a funo no tem
argumentos e qualquer chamada funo com parmetros um erro.
Quando uma funo sem prottipo chamada, todos os char so convertidos em int e
todos os float so convertidos em double. Tais converses, que esto relacionadas com
as caractersticas do ambiente original do C, acarretam uma alocao maior de
memria. No entanto, se a funo tem prottipo, os tipos especificados na declarao
do prottipo so mantidos.
Prof. Luiz Gustavo Almeida Martins Pg.: 6/82
Embora no seja um erro criar programas sem prottipo de funes, o padro ANSI recomenda
fortemente o seu uso.
UFU Universidade Federal de Uberlndia Faculdade de Computao
4. TIPOLOGIA DE DADOS
Durante a compilao do cdigo-fonte, o compilador C procura alocar o espao de memria
necessrio para a execuo do programa. Embora o compilador possa determinar os tipos de
dados e espao de memria exigidos para as constantes encontradas no cdigo, no caso das
variveis, isto s possvel se houver a declarao prvia do tipo de dado empregado.
Cada tipo de dado tem uma exigncia pr-determinada do tamanho de memria e uma faixa
associada de valores permitidos. Por exemplo, um caracter ocupa geralmente 1 byte, enquanto
que um inteiro tem normalmente 2 bytes. Entretanto, para garantir a portabilidade do cdigo C,
esta suposio no pode ser tomada como verdadeira. Isto porque, o tamanho e a faixa desses
tipos de dados variam de acordo com o tipo de processador e com a implementao do
compilador C. O padro ANSI estipula apenas a faixa mnima de cada tipo de dado e no o seu
tamanho em bytes.
4.1. TIPOS BSICOS
H 5 tipos bsicos em C, conforme tabela abaixo. Todos os demais tipos so variaes destes 5
tipos.
TIPOS BSICOS DE DADOS DO C
Tipos Descrio Tamanho Aprox. Faixa Mnima
char Caractere 8 bits =1 byte -127 a 127
int Inteiro 16 bits =2 bytes -32.767 a 32.767
float Ponto flutuante 32 bits =4 bytes 7 dgitos de preciso
double Ponto flutuante de preciso dupla 64 bits =8 bytes 10 dgitos de preciso
void Sem valor
Elementos do tipo char so normalmente utilizados para conter valores definidos pelo conjunto de
caracteres ASCII. Elementos do tipo int geralmente correspondem ao tamanho natural de uma
palavra do computador hospedeiro. Assim, numa mquina de 16 bits, int provavelmente ter 16
bits. Numa mquina de 32, int dever ter 32 bits. O formato exato dos elementos em ponto
flutuante depende de como eles so implementados. A faixa dos tipos float e double dada em
dgitos de preciso. J suas grandezas dependem do mtodo usado para representar os nmeros
em ponto flutuante. Qualquer que seja o mtodo, o nmero muito grande (o padro ANSI
especifica a faixa mnima de 1x10
-37
a 1x10
+37
). O tipo void declara explicitamente uma funo
que no retorna valor algum ou cria ponteiros genricos.
4.2. MODIFICADORES DE TIPODE DADOS
Com exceo dos tipos void e float, os demais tipos bsicos podem ser adaptados mais
precisamente s necessidades do problema estudado. Para isto, necessrio preceder o tipo
bsico do dado com um dos modificadores de tipo (signed, unsigned, long e short), visando
alterar o significado do tipo.
Prof. Luiz Gustavo Almeida Martins Pg.: 7/82
Normalmente, ao tipo double pode-se aplicar apenas o modificador long. Esta modificao gera
um tipo de ponto flutuante com maior preciso. Os quatro modificadores podem ser aplicados a
inteiros. Os modificadores short e long visam prover tamanhos diferentes de inteiros (inteiros
menores short int ou maiores long int). Na verdade, cada compilador livre para escolher
tamanhos adequados para o seu prprio hardware, com a nica restrio de que short int e int
devem ocupar pelo menos 16 bits e long int pelo menos 32 bits. Alm disso, short int no pode
ser maior que int, que, por sua vez, no pode ser maior que long int. O modificador unsigned
serve para especificar variveis sem sinal. Um unsigned int ser um inteiro que assumir apenas
valores positivos. J o uso de signed para o tipo int, apesar de permitido, redundante. A seguir
UFU Universidade Federal de Uberlndia Faculdade de Computao
esto listados os tipos de dados permitidos e seu valores mximos e mnimos em um compilador
tpico para um hardware de 16 bits. Tambm nesta tabela est especificado o formato que deve
ser utilizado para ler os tipos de dados com a funo scanf():
TIPOS DE DADOS MODIFICADOS
Intervalo
Tipo Num de bits
Formato
para leitura
com scanf
Inicio Fim
Char 8 %c -128 127
unsigned char 8 %c 0 255
Signed char 8 %c -128 127
Int 16 %i ou %d -32.768 32.767
unsigned int 16 %u 0 65.535
signed int 16 %i ou %d -32.768 32.767
Short int 16 %hi ou %hd -32.768 32.767
unsigned short int 16 %hu 0 65.535
signed short int 16 %hi ou %hd -32.768 32.767
Long int 32 %li ou %ld -2.147.483.648 2.147.483.647
signed long int 32 %li ou %ld -2.147.483.648 2.147.483.647
unsigned long int 32 %lu 0 4.294.967.295
Float* 32 %f, %e ou %g 3,4E-38 3.4E+38
Double* 64 %lf, %le ou %lg 1,7E-308 1,7E+308
long double* 80 %Lf 3,4E-4932 3,4E+4932
* importante observar que os intervalos de ponto flutuante, na tabela acima, esto indicados
em faixa de expoente, mas os nmeros podem assumir valores tanto positivos quanto negativos.
Por fim, dependendo da implementao de compilador utilizada, poder existir outros tipos de
dados (expandidos ou adicionais), como por exemplo, o uso do unsigned para os tipos de ponto
flutuante. Porm, o uso de tipos de dado no definidos pelo padro ANSI C reduz a
portabilidade de seu cdigo e, portanto, no recomendado.

char int
1 bit de sinal + 7 bits
de dados
1 bit de sinal + 15 bits de
dados

unsigned char unsigned int
8 bits de dados 16 bits de dados

float
1 bit de sinal + 8 bits de expoente + 23 bits
de mantissa (magnetude)
double

1 bit de sinal + 11 bits de expoente + 52 bits de mantissa (magnetude)

Representao Bsica de Armazenamento por Tipo de Dados
Prof. Luiz Gustavo Almeida Martins Pg.: 8/82
UFU Universidade Federal de Uberlndia Faculdade de Computao
4.3. MODIFICADORES DE TIPO DE ACESSO
O padro ANSI introduziu dois modificadores de tipo que controlam a maneira como as
variveis podem ser acessadas ou modificadas. Esses modificadores so const e volatile.
Estes modificadores devem preceder os modificadores de tipo de dado e/ou tipo de dados e o
nome das variveis que eles modificam.
Variveis do tipo const no podem ser modificadas pelo programa, podendo, entretanto,
receber um valor inicial. Por exemplo:
const int pi = 3.14;
O modificador volatile usado para informar ao compilador que o valor de uma varivel pode
ser alterado de maneira no explicitamente especificada pelo programa. Por exemplo, um
endereo de uma varivel global pode ser passado pra a rotina de relgio do sistema operacional
e usado para guardar o tempo real do sistema. Nessa situao, o contedo da varivel alterado
sem nenhum comando de atribuio explcito no programa.
possvel usar const e volatile juntos. Por exemplo, se 0x30 assumido como sendo o valor de
uma porta que mudado apenas por condies externas, a declarao seguinte ideal para
prevenir qualquer possibilidade de efeitos colaterais acidentais.
const volatile unsigned char *porta = 0x30;
Vale ressaltar que, qualquer valor que comece com 0x corresponde a um constante
hexadecimal, bem como valores iniciados com 0 equivalem a constantes octais. Assim, para o
compilador C, o valor 015 diferente de 15.
4.4. IDENTIFICADORES NO C
O padro ANSI define nomes de variveis, funes, rtulos e vrios outros objetos definidos pelo
usurio como identificadores. Esses identificadores podem variar de um a vrios caracteres,
sendo que o primeiro deve ser uma letra ou um caracter especial _ e os demais caracteres
devem ser letras, nmeros ou o caracter especial _ .
Vale ressaltar que, assim como na pseudolinguagem, o identificador NO PODE TER espao
nem nenhum outro caracter especial, inclusive letras acentuadas.
Os identificadores podem ter qualquer tamanho. Entretanto, de acordo com o uso do
identificador (interno ou externo chamado por outros programas), ele deve se diferenciar dos
demais (possuir um nome diferente de todos os outros identificadores utilizados) dentro de uma
margem pr-estabelecida (6 caracteres para nomes externos e 31 caracteres para nomes
internos).
Alm disso, um identificador no pode ser igual a uma palavra-chave de C ou a um nome de
funo j criada pelo usurio ou existente na bliblioteca padro.
OBS: Lembre-se que o C case-sensitive. Portanto, letras minsculas e maisculas so tratadas
diferentemente (ex: cont, CONT e Cont so trs identificadores diferentes).
4.5. DECLARAO DE VARIVEIS
Prof. Luiz Gustavo Almeida Martins Pg.: 9/82
Como j visto, uma varivel uma posio de memria de um determinado tipo de dado e que
possui um nome, que usada para guardar valores que podem sofrer mudanas durante a
execuo do programa.
UFU Universidade Federal de Uberlndia Faculdade de Computao
Todas as variveis do C devem ser declaradas antes de serem usadas. A forma geral de uma
declarao :
tipo lista_de_variveis;
Sendo:
Tipo: um tipo de dado vlido em C mais quaisquer modificadores; e
Lista_de_variveis: um ou mais nomes de identificadores separados por vrgula.
Exemplos:
int nro, idade, ndice;
short int idade;
double salario, pagamento;
As variveis podem ser declaradas em trs lugares bsicos: dentro de funes, na definio dos
parmetros das funes e fora de todas as funes. Estas so, respectivamente, variveis locais,
parmetros formais e variveis globais.
VARIVEIS LOCAIS
As variveis locais, tambm conhecidas com variveis automticas (pois pode utilizar o
especificador auto para declar-las), so aquelas declaradas dentro das funes e, portanto,
s so reconhecidas pela funo onde foi declarada (lembre-se que o corpo de uma funo
delimitado por chaves).
Variveis locais existem apenas enquanto o bloco de comando em que foram declaradas
est sendo executado. Isto , uma varivel local criada na entrada de seu bloco e destruda na
sada.
Ex: void func1()
{
int NRO;
NRO = 100;
}
void func2()
{
int NRO;
NRO = 0;
}
No exemplo acima, a varivel NRO declarada duas vezes (uma vez em cada funo) dentro do
programa. Observe que o NRO da func1 no tem nenhuma relao com o NRO da func2, j que
cada uma destas variveis s so reconhecidas nos seus respectivos blocos de comando.
Prof. Luiz Gustavo Almeida Martins Pg.: 10/82
A maioria dos programadores declara todas as variveis usadas por uma funo imediatamente
aps o abre chaves da funo. Porm, as variveis locais podem ser declaradas dentro de
qualquer bloco de comando, sempre aps o abre chaves e antes de qualquer outro
comando.
UFU Universidade Federal de Uberlndia Faculdade de Computao
Contra-Exemplo:
Exemplo:
void func()
{
int NRO;
NRO = 0;
char NOME[80];
gets(NOME);
}
/* Funo com declarao incorreta,
pois as variveis devem ser
declaradas no incio do bloco de
comandos, antes de qualquer outro
comando */
void func()
{
int NRO;
scanf (%d, &NRO);
if (NRO = = 0)
{
char NOME[80];
printf (Entre com o nome:);
gets(NOME);
}
}
Enquanto o trecho programa apresentado no exemplo acima funcionaria sem problemas, o trecho
de programa descrito no contra-exemplo no seria executado na maioria dos compiladores em C.
Uma das vantagens no uso de variveis locais evitar efeitos colaterais indesejados, decorrentes
de alteraes acidentais no valor das variveis fora da funo. Outra vantagem a reduo no
espao de memria alocado pelo compilador para execuo do programa.
PARMETROS FORMAIS
Se uma funo usa argumentos de entrada, ela deve declarar variveis que recebero os
valores desses argumentos. Essas variveis so denominadas parmetros formais da funo
e se comportam como qualquer outra varivel local da funo.
Como mostrado no exemplo abaixo, as declaraes dos parmetros formais de uma funo
ocorrem depois de seu nome e dentro de parnteses:
Exemplo:
int is_in(char *texto, char letra)
{
While (*texto)
{
if (*texto = = letra)
return 1;
else
texto++;
}
return 0;
}
Os parmetros formais declarados devem ser da mesma quantidade e tipo dos parmetros
utilizados na chamada da funo. Se houver alguma discordncia de tipo, resultados
inesperados podero ocorrer, uma vez que a linguagem C geralmente realiza alguma operao,
mesmo em situaes no usuais.
O padro ANSI fornece os prottipos de funes, que pode ser usado para ajudar a verificar se
os argumentos usados para chamar a funo so compatveis com os parmetros. Porm, para
receber esse benefcio extra, os prottipos de funes devem ser includos explicitamente no
programa. Mais detalhes sobre prottipos de funes podem ser vistos no prximo captulo.
Prof. Luiz Gustavo Almeida Martins Pg.: 11/82
UFU Universidade Federal de Uberlndia Faculdade de Computao
VARIVEIS GLOBAIS
Variveis globais so aquelas declaradas no incio do programa, fora de qualquer funo.
Ao contrrio das variveis locais, este tipo de varivel tem seus valores guardados durante toda a
execuo do programa, portanto, so reconhecidas no programa inteiro e podem ser usadas
por qualquer pedao de cdigo.
O armazenamento de variveis globais se encontra em uma regio fixa da memria, separada
para esse propsito pelo compilador C. Variveis globais so teis quando o mesmo dado
usado em muitas funes em seu programa. No entanto, deve-se evitar o uso desnecessrio
deste tipo de varivel, uma vez que elas ocupam memria durante todo o tempo de execuo do
programa e no apenas quando so necessrias.
4.6. ESPECIFICADORES DE TIPO DE CLASSE DE ARMAZENAMENTO
Existem 4 especificadores de classe de armazenamento suportados pelo C: extern, static,
register e auto. Esses especificadores so usados para informar ao compilador como a varivel
deve ser armazenada e deve preceder todo o resto da declarao, conforme a seguinte sintaxe:
especificador modificadores tipo_dado nome_varivel
EXTERN
Como j visto, uma varivel global s pode ser declarada uma nica vez dentro de um arquivo.
Assim, se declararmos em duplicidade uma varivel dentro do programa, o compilador C pode
apresentar uma mensagem de erro nome de varivel duplicado ou, simplesmente, escolher uma
das variveis. O mesmo problema ocorre quando declaramos variveis globais em cada
arquivo de um projeto. Embora o compilador no emita nenhuma mensagem, uma vez que a
compilao de cada arquivo feita separadamente, estaramos tentando criar duas ou mais
cpias de uma mesma varivel, e durante o processo de linkedio (que junta todos os arquivos
do projeto) seria mostrada a mensagem de erro rtulo duplicado.
O modificador extern utilizado para resolver este problema de duplicao. Isto , declara-se as
variveis globais em um nico arquivo, e nos demais repete-se a declarao da varivel,
precedida do modificador extern, como no exemplo:
STATIC
Variveis static so variveis permanentes. Isto , apesar de no serem reconhecidas fora de
suas funes ou arquivos, mantm seus valores entre as chamadas. Essa caracterstica torna
Prof. Luiz Gustavo Almeida Martins Pg.: 12/82
/*Programa 1*/
int x, y;
char z;
main(void)
{
}
func1()
{
x = 24;
y = x+3;
}
/*Programa 2*/
extern int x, y;
extern char z;
main(void)
{
}
Func2()
{
y = 33;
x = y-10;
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
este tipo de varivel til quando empregada em funes generalizadas e/ou de biblioteca, que
podem ser utilizadas por outros programadores. O especificador static tem efeitos diferentes em
variveis locais e globais.
Quando aplicado a uma varivel local, o compilador cria um armazenamento permanente,
quase da mesma forma que cria para variveis globais. A diferena fundamental entre elas que
a varivel local static reconhecida somente no bloco em que est declarada.
No exemplo abaixo, a varivel NRO_SERIE mantm seu valor entre as chamadas da funo
obtem_nro_serie. Isso significa que na primeira chamada ser produzido o nmero de srie 1010
e, a cada chamada da funo, um novo nmero ser criado com base no seu antecessor (ex:
1020, 1030, etc.).
Exemplo:
int obtem_nro_serie(void)
{
static int NRO_SERIE = 1000;
NRO_SERIE = NRO_SERIE + 10;
return (NRO_SERIE);
}
Aplicar o especificador static a uma varivel global, informa ao compilador para criar uma
varivel que reconhecida apenas no arquivo na qual a mesma foi declarada. Isto , embora
a varivel seja global, rotinas em outros arquivos no podem reconhec-la ou alterar seu contedo
diretamente.
AUTO
Por definio, as variveis no C so da classe automtica. O compilador automaticamente cria a
varivel cada vez que a funo chamada e elimina-a quando a funo finalizada.
O especificador auto instrui ao compilador para classificar uma varivel como automtica. O
uso deste especificador limitado, pois no se pode us-lo com variveis globais e as variveis
locais so automticas por default (padro).
REGISTER
O especificador register determina que o acesso varivel seja o mais rpido possvel .
Originalmente, quando este especificador era aplicado apenas variveis do tipo int e char, isto
significada colocar o contedo destas variveis nos registradores da CPU (da vem o nome do
especificador). Entretanto, como o padro ANSI ampliou o uso deste especificador aos demais
tipos de dados, tal tratamento foi modificado. No novo conceito do especificador, mantm-se o
armazenamento original para os tipos int e char e, para os demais tipos (ex: matrizes e vetores),
adota-se um tratamento diferenciado, de acordo com a implementao do compilador, visando
tornar rpido o acesso ao seu contedo. Porm, nestes casos no ocorre um aumento substancial
na velocidade de acesso.
Tal especificador s pode ser aplicado a variveis locais e parmetros formais, NO sendo
permitido o seu uso com variveis globais.
Prof. Luiz Gustavo Almeida Martins Pg.: 13/82
Alm disso, como variveis register podem ser armazenadas em um registrador da CPU, as
mesmas no podem ter endereos. Portanto, este especificador impede o uso do operador &.
UFU Universidade Federal de Uberlndia Faculdade de Computao
4.7. INICIALIZAO DE VARIVEIS
Na linguagem C, podemos inicializar uma varivel junto com sua declarao. Para isto, basta
colocar um sinal de igual e uma constante aps o nome da varivel, como no exemplo abaixo:
int NRO = 1000;
char LETRA = a, NOME[80] = Jos ;
Note que no exemplo acima a varivel NRO ser inicializada com 1000, a varivel LETRA
receber o caracter a e o vetor NOME receber a string J os. Vale ainda ressaltar que, neste
ltimo caso, cada letra da string ser associada a uma posio do vetor NOME, como ilustrado:
NOME[0] = J, NOME[1] = o, NOME[2] = s, NOME[3] = , NOME[4] = \0
Observe que, apesar da string de inicializao possuir apenas 4 caracteres, inserido um caracter
especial \0 (terminador nulo) na quinta posio do vetor (NOME[4]). Este caracter deve ser
utilizado nos testes condicionais das estruturas de controle (seleo ou repetio) para identificar
o final da string, como no exemplo:
void main(void)
{
char LETRA, FRASE[100];
int I = 0, CONT = 0;
printf(Digite uma frase:);
scanf(%s\n\n,&FRASE);
printf(Digite a letra que ser contada:);
scanf(%c\n\n,&LETRA);
while ((FRASE[I] != \0) && (I <= 100))
{
If (FRASE[I] = LETRA)
{
CONT++; /* Equivalente ao comando CONT = CONT+1 */
}
++I;
}
Printf(A letra %c apareceu %d vezes dentro da frase.\n, LETRA, CONT);
}
4.8. CONSTANTES
Constantes referem-se a valores fixos que o programa no pode alterar. No C, constantes podem
ser de qualquer um dos cinco tipos de dados bsicos e suas variaes.
Prof. Luiz Gustavo Almeida Martins Pg.: 14/82
Constantes de caracter so delimitadas por apstrofo [] (ex: a, %, 1). Caracteres
delimitados por aspas [ ] so tratados como constantes string (cadeia de caracteres),
portanto, ocupam um byte a mais na memria (ex: a =a +\0). Constantes inteiras so
especificadas como nmeros sem componentes fracionrios (ex: 69, -10). Constantes reais
podem ser expressas na forma decimal, neste caso requerido o ponto decimal [.] seguido da
parte fracionria (ex: 3.141, -7.33); ou atravs de notao cientfica (ex: 4.34e-3).
UFU Universidade Federal de Uberlndia Faculdade de Computao
Por default, o compilador C encaixa uma constante numrica no menor tipo de dado
compatvel que pode cont-la (ex: 10 int, 60000 unsigned int, 100000 log int). A nica
exceo esta regra so as constantes reais, as quais so assumidas como double. Apesar
de esta associao padro ser apropriada maioria dos programas, o programador pode forar a
associao de uma constante a outro tipo de dado, atravs da utilizao de um sufixo. Como por
exemplo, -15L (fora a utilizao do tipo long int) e 3.141F (fora a utilizao do tipo float).
Muitas vezes, precisamos inserir constantes hexadecimais (base dezesseis) ou octais (base oito)
no nosso programa. O C permite que se faa isto. As constantes hexadecimais comeam com
0x. As constantes octais comeam em 0.
Alguns exemplos:
0XEF /* Constante Hexadecimal (8 bits) */
0x12A4 /* Constante Hexadecimal (16 bits) */
03212 /* Constante Octal (12 bits) */
034215432 /* Constante Octal (24 bits) */
5. COMANDO DE ATRIBUIO
O comando de atribuio do C o sinal de igual (=). Ele utilizado para atribuir varivel da
esquerda o valor da varivel, constante ou expresso contida direita do sinal.
Sintaxe Geral:
Varivel = expresso;
Sendo expresso uma combinao de variveis, constantes e operadores.
5.1. OPERADORES
O C possui um grande conjunto de operadores que podem ser utilizados na manipulao de
variveis e constantes durante a execuo do programa.
OPERADORES ARITMTICOS
Os operadores aritmticos so usados para desenvolver operaes matemticas. A lista dos
operadores aritmticos do C apresentada a seguir:
OPERADORES ARITMTICOS DO C
Operador Finalidade
+ Soma (inteira e ponto flutuante)
- Subtrao ou Troca de Sinal (inteira e ponto flutuante)
* Multiplicao (inteira e ponto flutuante)
/ Diviso (inteira e ponto flutuante)
% Resto da Diviso (somente de inteiros)
Prof. Luiz Gustavo Almeida Martins Pg.: 15/82
Uma particularidade do C refere-se ao fato do valor retornado por uma expresso aritmtica
ser sempre do maior tipo de dado utilizado na expresso. Assim, uma diviso de nmeros
UFU Universidade Federal de Uberlndia Faculdade de Computao
inteiros retornar a parte inteira do resultado (diviso inteira), enquanto a diviso de nmeros do
tipo float retornar um valor do mesmo tipo (diviso de nmeros reais).
Todos os operadores descritos so binrios (aplicveis sobre duas variveis), exceto pelo
operador - quando aplicado para trocar o sinal de uma varivel. Neste caso o operador simula a
multiplicao da varivel por -1.
Abaixo so apresentados alguns exemplos de utilizao dos operadores aritmticos:
int A = 1, B = 2, C;
float X = 2.0, Y = 3.5, Z;
C = (2 * A + B) / B; /* C receber o valor 2 */
Z = X * Y + C; /* Z receber o valor 9.0 */
C = (A + B) % B; /* C receber o valor 1 */
C = -B; /* C receber o valor -2 */
OPERADORES DE INCREMENTO E DECREMENTO
A linguagem C permite a utilizao dos operadores unrios ++ e -- para incrementar (somar 1)
ou decrementar (subtrair 1) o contedo de uma varivel, respectivamente. Apesar destes
operadores no serem aceitos em outras linguagens, eles possuem uma grande utilidade,
principalmente na manipulao de variveis contadoras. Abaixo so apresentados alguns
exemplos de sua utilizao:
++X; /* Equivalente expresso X = X + 1 */
X++; /* Equivalente expresso X = X + 1 */
--X; /* Equivalente expresso X = X - 1 */
X--; /* Equivalente expresso X = X - 1 */
Como pode ser notado, estes operadores podem ser pr-fixados ou ps-fixados. A diferena
que quando so pr-fixados, eles incrementam a varivel antes de usar seu valor. Quando so
ps-fixados, eles utilizam o valor da varivel antes de increment-la. Para entender melhor esta
diferena, veja os exemplos abaixo:
int X = 10, Y;
Y = X++;
/* Neste caso Y = 10 e X = 11 */
int X = 10, Y;
Y = ++X;
/* Neste caso Y e X = 11 */
EXPRESSES REDUZIDAS
As expresses reduzidas so aplicadas nos casos que uma mesma varivel se encontra em
ambos os lados do comando de atribuio. A forma geral destas expresses :
varivel operador = expresso;
EXEMPLO DE UTILIZAO DE EXPRESSES REDUZIDAS
Prof. Luiz Gustavo Almeida Martins Pg.: 16/82
Expresses Reduzidas Expresses Normais
A += 5; A = A + 5;
B - = 2.5; B = B 2.5;
UFU Universidade Federal de Uberlndia Faculdade de Computao
Expresses Reduzidas Expresses Normais
C *= 2; C = C * 2;
D /= 7; D = D / 7;
E %= 3; E = E % 3;
Note que este tipo de expresso muito til para a manipulao de variveis contadoras e/ou
acumuladoras (que envolve somatrias, totais, etc.).
OPERADORES RELACIONAIS E LGICOS
Os operadores relacionais realizam comparaes entre expresses, e seus resultados sempre
so valores lgicos (falso valores iguais a zero ou verdadeiro valores diferentes de zero).
OPERADORES RELACIONAIS
Operador Finalidade
== Igual
> Maior
< Menor
>= Maior e igual
<= Menor e igual
!= Diferente
Alm dos operadores relacionais, a linguagem C ainda dispe de operadores lgicos. Estes
operadores podem ser utilizados para agrupar duas ou mais operaes relacionais em um nico
teste condicional (operadores binrios AND e OR) ou, ainda, modificar o resultado de uma
operao relacional (operador unrio NOT).
OPERADORES LGICOS
Operador Finalidade
&& AND (E)
|| OR (OU)
! NOT (NO)
Abaixo apresentado um programa exemplo que imprime os nmeros pares entre 1 e 100.
Observe neste exemplo que, quando o nmero par, seu mdulo igual a 0. Portanto, utilizando
o operador NOT, podemos converter este resultado para 1 (verdadeiro), disparando a clusula
ento da estrutura de seleo IF (a qual ser vista mais adiante).
# include <stdio.h>
void main(void)
{
int NRO;
for (NRO = 1; NRO <= 100; NRO++)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 17/82
If ( !(NRO%2)) /* Verifica se o N par ou mpar */
UFU Universidade Federal de Uberlndia Faculdade de Computao
Printf(O nmero %d par., NRO);
}
}
5.2. EXPRESSES CONDICIONAIS
O operador ternrio ? permite a atribuio condicional de valores a uma varivel. Ele fornece
uma forma alternativa de escrever uma tomada de deciso, atravs da seguinte sintaxe:
condio ? expresso1 : expresso2
Nesta estrutura, a condio testada e, caso seja verdadeira, a expresso1 assumida; seno
adotada a expresso2. Para exemplificar sua utilizado, segue abaixo um trecho de um programa
que atribui varivel Z o maior valor entre as variveis A e B:
Z = (A > B) ? A : B; /* Equivalente a Z = max(A,B) */
Outra forma de escrever este comando seria:
if (A > B)
Z = A;
else
Z = B;
5.3. CONVERSO ENTRE TIPOS DE DADOS
Quando uma expresso combina variveis de tipos de dado diferentes, o compilador C verifica se
as converses entre estes tipos so possveis. Caso no sejam, o processo de compilao
interrompido e uma mensagem de erro exibida. Caso contrrio, o compilador realiza todas as
converses necessrias, seguindo as seguintes regras:
1. Todos os char e short int so convertidos para int. Todos os float so convertidos para
double.
2. Para pares de operandos de tipos diferentes: os de menor capacidade so convertidos
para os de maior capacidade (ex: se um deles long double, o outro tambm
convertido para long double).
Alm disso, o programador pode forar que o resultado de uma expresso seja de um
determinado tipo. Para isto, ele deve utilizar operadores cast (modeladores). Sua forma geral :
varivel = (tipo_dado) expresso;
Abaixo apresentado um exemplo da a utilizao de operadores cast:
# include <stdio.h>
void main(void)
{
int NRO;
float RESULTADO;
scanf(%d, &NRO);
RESULTADO = (float) NRO/2; /* Fora a converso de NRO em float */
printf(\nA metade de %d %f, NRO, RESULTADO);
Prof. Luiz Gustavo Almeida Martins Pg.: 18/82
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
Note que, se no tivssemos utilizado o operador cast no exemplo acima, primeiro seria feito a
diviso inteira de NRO por 2 e, depois, o resultado seria convertido para float.
5.4. PRECEDNCIA DE OPERADORES
Abaixo apresentada a tabela de precedncia dos operadores na linguagem C:
PRECEDNCIA DOS OPERADORES
Operadores Sentido de Execuo
( ) [ ] Esquerda p/ Direita
++ -- - (unrio) (cast) Direita p/ Esquerda
* / %
+ - (binrio)
< > <= >=
== !=
!
&&
||
?: (expresso condicional)
Esquerda p/ Direita
= += *= /= - = Direita p/ Esquerda
A seqncia das linhas indica a prioridade dos operadores, ou seja, os operadores
localizados mais acima na tabela sero executados primeiro que aqueles descritos no final da
tabela. Alm disso, operadores descritos na mesma linha possuem a mesma precedncia.
6. FUNES DISPONVEIS NO C
6.1. FUNES MATEMTICAS
Na tabela abaixo so apresentadas algumas das funes matemticas disponveis na linguagem
C. Para utiliza-las necessrio declarar o arquivo de cabealho math.h.
FUNES MATEMTICAS DO C
Prof. Luiz Gustavo Almeida Martins Pg.: 19/82
Funo Sintaxe Descrio
ceil() ceil(REAL) Arredonda a varivel REAL para cima (ex: ceil(3.4) =4)
cos() cos(NRO) Calcula o cosseno de NRO (NRO em radianos)
exp() exp(NRO) Calcula e elevado potncia NRO
fabs() fabs(NRO) Calcula o valor absoluto de NRO
floor() floor(REAL) Arredonda a varivel REAL para baixo (ex: floor(3.4) =3)
log() log(NRO) Calcula o logaritmo natural de NRO
log10() log10(NRO) Calcula o logaritmo decimal de NRO
UFU Universidade Federal de Uberlndia Faculdade de Computao
Funo Sintaxe Descrio
pow() Pow(BASE,EXP) Calcula o valor de BASE elevado potncia EXP
sin() sin(NRO) Calcula o seno de NRO (NRO em radianos)
sqrt() sqrt(NRO) Calcula a raiz quadrada de NRO.
tan() tan(NRO) Calcula a tangente de NRO (NRO em radianos)
Alm das operaes de exponenciao, a funo pow() tambm realiza operaes de
radiciao, uma vez que tal operao pode ser representada como uma exponenciao com o
expoente fracionrio.
exemplo:
3
1
3
X X =
6.2. FUNES TOLOWER() E TOUPPER()
As funes tolower() e toupper() esto definidas no arquivo de cabealho ctype.h e tm por
finalidade, converter uma letra maiscula em minscula e vice-versa, respectivamente. Suas
sintaxes so:
varivel_char = tolower(caracter);
varivel_char = toupper(caracter);
Qualquer caracter diferente de letra retornado sem modificaes.
A seguir apresentado um exemplo de utilizao destas funes:
#include <stdio.h>
#include <ctype.h>
void main(void)
{
char LETRA;
LETRA = getchar();
putchar( tolower(LETRA));
putchar( toupper(LETRA));
}
6.3. FUNO CLRSCR()
A funo clrscr() utilizada para limpar todo o contedo da tela e posicionar o cursor no seu
incio, ou seja, canto superior esquerdo da tela (linha 1 , coluna 1). Sua forma geral :
clrscr();
Para utilizar esta funo necessrio declarar o arquivo de cabealho conio.h, conforme
apresentado no exemplo abaixo:
#include <stdio.h>
#include <conio.h>
void main(void)
Prof. Luiz Gustavo Almeida Martins Pg.: 20/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
printf(Esta a primeira linha\n);
printf(Esta a segunda linha\n);
printf(Esta a terceira linha\n);
clrscr();
printf(Esta a nova primeira linha\n);
printf(Esta a nova segunda linha\n);
}
6.4. FUNO GOTOXY()
A funo gotoxy() utilizada para posicionar o cursor na posio (coordenadas de linha e coluna)
desejada. Sua forma geral :
gotoxy(coluna, linha);
Para utilizar esta funo necessrio declarar o arquivo cabealho conio.h, conforme
apresentado no exemplo abaixo:
#include <stdio.h>
#include <conio.h>
void main(void)
{
int LINHA, COLUNA;
char TEXTO[10];
printf(Digite a linha e coluna onde deseja escrever o texto:);
scanf(%d,%d, &LINHA, &COLUNA);
printf(\nDigite o texto a ser mostrado:);
gets(TEXTO);
clrscr();
gotoxy(COLUNA, LINHA);
puts(TEXTO);
}
7. COMANDOS DE ENTRADA E SADA
7.1. PRINTF()
A funo printf() possibilita a sada de valores (constantes, variveis ou resultados de
expresses). Esta funo converte e imprime seus argumentos na sada padro seguindo o
formato especificado na string de controle. Sua sintaxe geral :
printf( string de controle , lista de argumentos);
A string de controle, delimitada por aspas, descreve tudo que a funo ir colocar na tela. Esta
string no mostra apenas os caracteres que devem sero apresentados, mas tambm os
respectivos formatos e posies das constantes, variveis e expresses listadas na lista de
argumentos. Assim, resumidamente, podemos dizer que a string de controle consiste de trs
tipos de caracteres:
Prof. Luiz Gustavo Almeida Martins Pg.: 21/82
Caracteres diversos que sero impressos na tela (correspondem ao texto que ser
exibido);
UFU Universidade Federal de Uberlndia Faculdade de Computao
Caracteres especiais de escape \, utilizados para auxiliar na movimentao do cursor
na tela ou do carro de impresso (alguns destes caracteres sero vistos na seo 7.7); e
Caracteres especificadores de formato % , que definem a posio e a maneira como
cada uma das variveis contidas na lista de argumentos sero exibidas (tipo e tamanho
do dado).
ALGUNS ESPECIFICADORES DE FORMATO DA FUNO PRINTF()
Especificador
Tipo do
Argumento
Descrio
%d int Valor inteiro decimal
%i int Valor inteiro decimal
%o int Valor inteiro octal
%x int Valor inteiro hexadecimal
%X int Valor inteiro hexadecimal
%u int Valor inteiro decimal sem sinal (unsigned int)
%c int Um caracter em formato ASCII (cdigo binrio correspondente)
%s char Uma cadeia de caracteres (string) terminada em \0
%f float
Valor em ponto flutuante no formato [-]m.dddddd, onde o N de
ds dado pela preciso (padro 6)
%e float ou double
Valor em ponto flutuante em notao exponencial no formato
[-]m.ddddd exx, onde o N de ds dado pela preciso
%E float ou double
Valor em ponto flutuante em notao exponencial no formato
[-]m.ddddd Exx, onde o N de ds dado pela preciso
%g float ou double
Valor em ponto flutuante no formato %e (quando o expoente
for menor que -4 ou igual a preciso) ou %f (nos demais
casos). Zeros adicionais e um ponto decimal final no so
impressos
%G float ou double
Valor em ponto flutuante no formato %E (quando o expoente
for menor que -4 ou igual a preciso) ou %f (nos demais
casos). Zeros adicionais e um ponto decimal final no so
impressos
%% - Exibe o caracter %
Entre o caracter % e o caracter especificador do tipo de dado pode vir as seguintes alternativas:
Um sinal de menos que determina o ajustamento/alinhamento esquerda do argumento
convertido;
Um nmero que especifica a largura (tamanho) mnima do campo que receber o
argumento convertido. Se necessrio, ele ser preenchido com espao esquerda (ou
direita, se o ajustamento esquerda for solicitado) para compor a largura do campo;
Prof. Luiz Gustavo Almeida Martins Pg.: 22/82
Um ponto que separa a largura do campo da sua preciso (N de casas decimais);
UFU Universidade Federal de Uberlndia Faculdade de Computao
Um nmero ou a preciso, que especificam o nmero mximo de caracteres a ser
impresso em uma string, ou o nmero de dgitos aps o ponto decimal de um valor real, ou
o nmero mnimo de dgitos para um inteiro;
Um h ou l se o nmero inteiro tiver que ser impresso como short ou long,
respectivamente.
Exemplos:



Um programa exemplo ilustrando o uso destes especificadores de formato na funo printf()
apresentado a seguir:
#include <stdio.h>
void main(void)
{
short int CH = 47;
printf(%-10.2f %-10.2f %-10.2f \n, 8.0, 15.253, 584.13);
printf(%04d \n, 21);
printf(%6d \n, 21);
printf(%10.3f \n, 3456.78);
printf(%3.1f \n, 3456.78);
printf(%hd %c \n, CH);
}
Este programa exemplo reproduzir as seguintes sadas:
8.00 15.25 584.13 /* Alinhamento esquerda (espaos direita)*/
0021 /*O N complementado com zeros esquerda*/
21 /*O N complementado com espaos esquerda */
3456.780
3456.8 /* A parte fracionada arredondada para 1 casa */
47 / /* 47 o cdigo ASCII do caracter / */
Prof. Luiz Gustavo Almeida Martins Pg.: 23/82
2 2 %4d
2 2 %-4d
2 2 2 . %7.2f
2 2 2 . %-7.2f
4 2
7
UFU Universidade Federal de Uberlndia Faculdade de Computao
7.2. SCANF()
A funo scanf() l caracteres da entrada padro (teclado), interpreta-os segundo a especificao
de formato e armazena os resultados em variveis declaradas no programa. Sua forma geral :
scanf ( string de controle , lista de endereos de memria das variveis);
A representao do endereo de memria das variveis que recebero os dados de entrada
fornecido pelo operador & , seguido pelo nome da varivel. Alm disso, assim como na
funo printf(), esta funo tambm utiliza os caracteres especiais de controle via cdigos de
barra invertida (veja seo 7.7) e de formatao % (conforme apresentado na tabela abaixo).
ALGUNS ESPECIFICADORES DE FORMATO DA FUNO SCANF()
Especificador Descrio
%d Indica um valor inteiro decimal
%i
Indica um valor inteiro (podendo estar na base
decimal, octal com inicial 0 (zero) ou hexadecimal
com inicial 0X
%u Indica um valor inteiro decimal sem sinal
%c Indica um caracter (char)
%s Indica uma string
%f, %e, %g
Indica um valor em ponto flutuante de preciso
simples (float)
%lf, %le, %l g
Indica um valor em ponto flutuante de preciso dupla
(double)
%o Indica um valor inteiro octal (com ou sem zero inicial)
%x ou %X
Indica um valor inteiro hexadecimal (com ou sem
0x inicial)
No exemplo abaixo, a funo scanf() ler o nmero digitado como float, armazenando-o no
endereo da varivel NRO. Os nmeros digitados sero somados at que seja digitado CTRL-Z.
Como sada sero apresentados a soma parcial (subtotal) a cada dez nmeros lidos e o total geral
ao final do programa.
# include <stdio.h>
void main(void)
{
float SOMA, NRO;
int CONT;
CONT = SOMA = 0;
printf (\n Entre com os nmeros a serem somados ou digite CTRL-Z para terminar |n);
while (scanf (%f, &NRO) == 1)
{
CONT++;
if (CONT == 10)
{
printf(\t Subtotal: %.2f \n, SOMA += NRO);
CONT = 0;
}
Prof. Luiz Gustavo Almeida Martins Pg.: 24/82
else
UFU Universidade Federal de Uberlndia Faculdade de Computao
SOMA += NRO;
}
printf (\t Total: %.2f \n, SOMA);
}
7.3. GETCHAR()
A macro getchar() retorna o prximo caracter de entrada toda vez que chamada, ou EOF (End
Of File) quando for fim de arquivo. Esta macro interpreta o caracter de entrada pelo seu valor
ASCII, ou seja, seu retorno um nmero inteiro, correspondente ao cdigo binrio do caracter
lido. Ela usa uma tcnica chamada de entrada bufferizada , ou seja, os caracteres digitados
pelo usurio no esto disponveis para a macro getchar() at que seja pressionada a tecla
<ENTER>.
A forma bsica de utilizao desta macro :
varivel = getchar();
No programa exemplo abaixo, ser impresso o cdigo ASCII correspondente ao caracter digitado.
#include <stdio.h>
#include <conio.h>
void main(void)
{
int NUM;
clrscr();
printf (\nEntre com um caracter ou tecle espao para terminar: );
while ((NUM = getchar()) != )
{
if (NUM != 10)
{
printf(\n\tCaracter\tCdigo ASCII\n\n\t %c \t %d\n, NUM, NUM);
printf(\nEntre com um caracter ou tecle espao para terminar: );
}
}
getchar();
}
Neste exemplo, a linha getchar(); utilizada para manter a exibio da tela do DOS at que um
caracter qualquer seja pressionado.
Obs: o arquivo de cabealho stdio.h contm a declarao do identificador EOF (#define EOF -1).
7.4. GETCH() e GETCHE()
Prof. Luiz Gustavo Almeida Martins Pg.: 25/82
As funes getch() e getche() retornam o caracter pressionado. A funo getche() imprime o
caracter na tela antes de retorn-lo, enquanto que a funo getch() apenas retorna o caracter
sem imprimi-lo. Ambas so definidas no arquivo de cabealho conio.h, portanto, no pertencem
ao padro ANSI. A sintaxe destas funes similar a da macro getchar().
UFU Universidade Federal de Uberlndia Faculdade de Computao
7.5. GETS()
A funo gets() l uma string e coloca-a no endereo apontado pelo seu argumento ponteiro para
caractere. Para efeito prtico, far parte da string tudo o que for digitado at o retorno do carro
(tecla <ENTER>), sendo este substitudo pelo terminador nulo \0. Sua sintaxe geral :
gets(nome_variavel);
Se for ultrapassado o espao reservado para a string, esta funo sobrepe os valores na
memria, podendo ocasionar um erro grave.
A seguir apresentado um programa exemplo da funo gets().
# include <stdio.h>
void main(void)
{
char MSG[21];
printf(\n\nDigite uma mensagem com no mximo 20 caracteres: );
gets(MSG);
printf(\n\nA mensagem digitada : %s, msg);
getchar();
}
7.6. PUTS()
A funo puts() apresenta na tela a string passada como argumento, seguida de uma nova linha
(\n). Ela retorna um valor no negativo se houver sucesso no processo ou, caso contrrio, retorna
EOF. Sua forma geral :
puts(string);
Esta funo reconhece os mesmos caracteres especiais de escape (backslash \ ) que a
funo printf(). Entretanto, uma chamada funo puts() requer menos esforo de
processamento que a mesma chamada para a funo printf(), uma vez que a primeira pode
enviar somente strings, enquanto que a segunda, alm de strings, pode enviar outros tipos de
dados, bem como fazer converso de formatos. Portanto, a funo puts() ocupa menos espao
de memria e executada mais rapidamente que a funo printf(). A seguir apresentado um
exemplo de sua utilizao.
#include <stdio.h>
void main(void)
{
char STRING[10];
puts(Exemplo de utilizao da funo puts.\n Entre com uma string:);
gets(STRING);
puts(\n A string digitada foi:);
puts(STRING);
}
7.7. PUTCHAR()
Prof. Luiz Gustavo Almeida Martins Pg.: 26/82
A macro putchar() coloca um nico caracter na sada padro. Sua sintaxe geral :
UFU Universidade Federal de Uberlndia Faculdade de Computao
putchar(varivel);
A varivel passada como argumento para a macro pode ser do tipo int (contendo o cdigo binrio
do caracter desejado) ou char.
Alm disso, assim como a funo puts(), ela retorna EOF em caso de erro.
No exemplo a seguir, a macro utilizada para apresentar na sada padro (que por default a
tela) os caracteres digitados pelo usurio em letras minsculas.
#include <stdio.h>
#include <ctype.h>
void main(void)
{
char C;
puts(Entre com os caracteres desejados ou tecle CTRL-Z para terminar:\n);
while ((C = getchar()) != EOF)
putchar (tolower(C));
}
7.8. CARACTERES DE ESCAPE
Para nos facilitar a tarefa de programar, a linguagem C disponibiliza vrios cdigos chamados
cdigos de barra invertida - backslash ou caracteres de escape. Uma lista com os principais
cdigos dada a seguir:
CDIGOS DE BARRA INVERTIDA
Cdigo Significado
\a Sinal sonoro ("beep")
\b Retrocesso (backspace)
\n Mudana de linha (new line)
\f Avano de pgina (form feed)
\r Retorno do carro da impressora
\t Tabulao horizontal (tab)
\v Tabulao vertical
\0 Nulo (0 em decimal)
\\ Impresso da barra invertida
\ Impresso das aspas
\ Impresso do apstrofo
\? Impresso do ponto de interrogao
\N Constante octal (N o valor ASCII em octal)
\xN Constante hexadecimal (N o valor ASCII em hexa)
Prof. Luiz Gustavo Almeida Martins Pg.: 27/82
Estes caracteres de controle podem ser usados como qualquer outro dentro das strings de
controle das funes printf() e scanf().
UFU Universidade Federal de Uberlndia Faculdade de Computao
8. ESTRUTURAS DE SELEO OU DECISO
Este tipo de estrutura permite direcionar o fluxo lgico do programa para blocos distintos de
instrues, conforme uma condio de controle (normalmente avaliao de expresses lgicas
e/ou relacionais).
8.1. COMANDO IF
O comando if o principal comando para codificar a tomada de deciso em C. Basicamente, ele
examina a condio especificada e, se a condio for verdadeira (diferente de zero), o programa
executa o bloco de comandos que segue; caso contrrio, ou seja, se a condio for falsa
(igual a zero), o bloco de comandos no ser executado.
A sintaxe geral do comando if a seguinte:
If (condio)
{
bloco de comandos;
}
O bloco de comandos deve ser delimitado por uma chave aberta e uma fechada. No entanto, se o
bloco composto por apenas um nico comando, as chaves se tornam opcionais e podem
ser omitidas.
Um exemplo de utilizao deste comando apresentado a seguir:
#include <stdio.h>
int main (void)
{
int a,b;
printf(Digite dois nmeros inteiros: );
scanf(%d %d, &a, &b);
if ((a < 0) && (b < 0))
{
printf(\nForam digitados 2 nmeros negativos.);
}
return 0;
}
8.1.1. CLUSULA ELSE
A incluso da clusula else permite que um segundo bloco de comandos seja executado, caso a
condio testada pelo comando if seja falsa (igual a zero). Sua forma geral :
If (condio)
{
bloco de comandos 1; /* Executado quando a condio for verdadeira */
}
else
{
Prof. Luiz Gustavo Almeida Martins Pg.: 28/82
bloco de comandos 2; /* Executado quando a condio for falsa */
UFU Universidade Federal de Uberlndia Faculdade de Computao
}
A seguir apresentado um exemplo da utilizao deste comando. Este programa tem como
entrada um nmero inteiro e sua sada uma frase informando se o nmero fornecido par ou
mpar.
#include <stdio.h>
void main (void)
{
int NRO;
printf(Digite um nmero inteiro: );
scanf(%d, &NRO);
if (NRO%2 == 0)
printf(\nO nmero par);
else
printf(\nO nmero mpar);
}
Neste programa no foram utilizadas as chaves para delimitar os blocos do comando if-else. Alm
disso, observe que os blocos de comandos esto endentados (recuo de linha) estrutura a qual
pertencem. Como j visto em algoritmos, esta endentao no obrigatria, mas fundamental
para uma maior clareza do cdigo, uma vez que permite identificar visualmente o incio e fim de
cada bloco. Todavia, nem sempre o uso da endentao aliado remoo das chaves facilita
a associao dos blocos de comandos a suas respectivas estruturas, como apresentado no
contra-exemplo abaixo:
#include <stdio.h>
void main (void)
{
int TEMP;
printf(Digite a temperatura: );
scanf(%d, &TEMP);
if (TEMP < 30)
if (TEMP > 20)
printf(\nTemperatura agradvel);
else
printf(\nTemperatura muito quente);
}
A idia desse programa era imprimir a mensagem Temperatura agradvel se fosse fornecido um
valor entre 20 e 30 e imprimir a mensagem Temperatura muito quente se fosse fornecido um
valor maior que 30. Entretanto, neste caso, a segunda mensagem ser exibida quando a
temperatura for menor ou igual a 20. Isto porque, na linguagem C, um else associado ao
ltimo if que no tiver seu prprio else. Assim, nos casos onde tal associao no
apropriada, deve-se criar explicitamente os blocos de comando atravs do emprego das
chaves. Abaixo apresentado o programa com as alteraes necessrias ao bom funcionamento:
#include <stdio.h>
void main (void)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 29/82
int TEMP;
UFU Universidade Federal de Uberlndia Faculdade de Computao
printf(Digite a temperatura: );
scanf(%d, &TEMP);
if (TEMP < 30)
{
if (TEMP > 20)
printf(\nTemperatura agradvel);
}
else
printf(\nTemperatura muito quente);
}
8.1.2. NINHOS DE IF
Na linguagem C, assim como j apresentado em algoritmos, possvel utilizar-se de
aninhamentos de comandos if. Isto , um comando if pode conter outros comandos ifs dentro de
seus blocos de comandos.
Exemplo:
#include <stdio.h>
void main(void)
{
int TEMP;
printf(Digite a temperatura: );
scanf(&d, &TEMP);
if (TEMP < 20)
{
if (TEMP < 10)
printf(\nTemperatura muito fria.);
else
printf(\nTemperatura fria.);
}
else
{
if (TEMP < 30)
printf(\nTemperatura agradvel.);
else
printf(\nTemperatura quente.);
}
}
8.1.3. CLUSULA ELSE IF
A clusula else if usada para escrever decises com escolhas mltiplas (teste de vrias
condies). Funciona de forma similar ao aninhamento de comandos if dentro do blocos de
comandos das clusulas else dos ifs superiores. Sua sintaxe geral :
If (condio1)
Prof. Luiz Gustavo Almeida Martins Pg.: 30/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
bloco de comandos 1; /* Executado quando a condio1 for verdadeira */
}
else if (condio2)
{
bloco de comandos 2; /* Executado quando a condio2 for verdadeira */
}
else if (condio3)
{
bloco de comandos 3; /* Executado quando a condio3 for verdadeira */
}



else if (condioN)
{
bloco de comandos N; /* Executado quando a condioN for verdadeira */
}
else
{
bloco de comandos (N+1); /* Executado quando todas as condies
anteriores forem falsas */
}
Nesta estrutura, as expresses condicionais so avaliadas em ordem e, se alguma delas for
verdadeira, o bloco de comandos correspondente ser executado e o encadeamento ser
finalizado (nenhuma outra condio da estrutura ser testada).
Abaixo apresentado uma modificao do programa anterior, contendo a clusula else if:
#include <stdio.h>
void main(void)
{
int TEMP;
printf(Digite a temperatura: );
scanf(&d, &TEMP);
if (TEMP < 10)
printf(\nTemperatura muito fria.);
else if (TEMP < 20)
printf(\nTemperatura fria.);
else if (TEMP < 30)
printf(\nTemperatura agradvel.);
else
printf(\nTemperatura quente.);
}
8.2. COMANDO SWITCH
Prof. Luiz Gustavo Almeida Martins Pg.: 31/82
Em um comando switch, o computador compara uma varivel sucessivamente contra uma
lista de constantes. Caso uma das constantes descrita nas clusulas case seja igual ao valor
UFU Universidade Federal de Uberlndia Faculdade de Computao
atual da varivel, o computador executa o comando ou bloco de comandos que estejam
associados quela opo.
Este tipo de estrutura difere do if, pois s pode testar igualdade, enquanto o if pode testar
qualquer tipo de expresso lgica.
A sua sintaxe geral :
switch (varivel_testada)
{
case valor_1: {
bloco-comandos;
break;
}
case valor_2: {
bloco-comandos;
break;
}



case valor_N: {
bloco-comandos;
break;
}
default: {
bloco-comandos;
}
}
O comando break usado para terminar uma seqncia de comandos. Tecnicamente o seu
uso opcional. Entretanto, quando omitido, a execuo continuar nos comandos do prximo
case at que o computador encontre um break ou o fim do comando switch - case.
A clusula default tambm opcional e serve para tratar os casos que no se enquadram
nas condies testadas nas clusulas case. Se no for utilizado, nenhum comando ser
executado caso todas as opes case falhem.
O comando switch freqentemente utilizado na construo de menus, como ilustrado no
exemplo a seguir:

/* construcao de menu utilizando o comando switch - case */

#include <stdio.h>
#include <conio.h>

main()
{

float x,y,r;
char op;

clrscr();
printf ("Entre com o 1 valor: ");
scanf("%f", &x);
printf ("Entre com o 2 valor: ");
scanf("%f", &y);
op = 0;
Prof. Luiz Gustavo Almeida Martins Pg.: 32/82
while (op !='5')
UFU Universidade Federal de Uberlndia Faculdade de Computao
{
clrscr();
printf ("Menu Principal\n");
printf ("1. Soma \n");
printf ("2. Subtracao \n");
printf ("3. Multiplicacao \n");
printf ("4. Divisao\n");
printf ("5. Sair\n");
printf ("Escolha uma das opes acima:");
op = getche();
clrscr();
if (op!='5')
{
switch (op)
{
case '1': {
printf (" Calculo da Soma \n");
r = x+y;
printf (" %.1f + %.1f = %.1f ", x,y,r);
getch();
break;
}
case '2': {
printf (" Calculo da Subtracao \n");
r = x-y;
printf (" %.1f - %.1f = %.1f ", x,y,r);
getch();
break;
}
case '3': {
printf (" Calculo da Multiplicacao \n");
r = x*y;
printf (" %.1f x %.1f = %.1f ", x,y,r);
getch();
break;
}
case '4': {
printf (" Calculo da Divisao \n");
if (y != 0)
{
r = x/y;
printf (" %.1f / %.1f = %.1f ", x,y,r);
}
else printf(" Divisao por zero!");
getch();
break;
}
default:{
printf("Opo invlida!");
getch();
}
} /* fim do switch */
} /* fim do if */

} /* fim do while */
}
9. ESTRUTURAS DE REPETIO
Prof. Luiz Gustavo Almeida Martins Pg.: 33/82
Permite executar repetidamente um bloco de instrues ate que uma condio de controle seja
satisfeita.
UFU Universidade Federal de Uberlndia Faculdade de Computao
9.1. COMANDO WHILE
O comando while executa um bloco de comandos enquanto a condio testada for verdadeira
(diferente de zero). Sua sintaxe geral :
while (condio de teste)
{
boco_comandos;
}
Este comando verifica a condio de teste no incio do loop . Isto significa que o seu bloco
de comandos poder ou no ser executado, de acordo com o resultado desta verificao.
Abaixo apresentado um programa exemplo deste comando:
# include <stdio.h>
void main(void)
{
int i = 1, soma = 0;
while (i <= 10)
{
soma += i;
i++;
}
printf(A soma dos nmeros inteiros de 1 a 10 %d, soma);
getchar();
}
Caso a condio testada seja um nmero ou uma expresso matemtica, o loop ser executado
at que o valor do nmero ou da expresso seja igual a zero.
Assim como no comando if, se o bloco de comando for formado por uma nica instruo, no
necessrio utilizar as chaves.
9.2. COMANDO DO WHILE
O comando do while similar ao comando while, exceto pelo fato que, ele primeiro executa o
bloco de comandos para depois verificar a condio de teste, ou seja, neste comando, as
instrues contidas no loop so executadas pelo menos uma vez. Alm disso, se a condio
testada for verdadeira, o bloco de comandos ser novamente executado at que a condio
de teste se torne falsa. Sua sintaxe geral :
do
{
bloco_comandos;
} while (condio de teste);
Abaixo apresentado um exemplo de utilizao deste comando:
# include <stdio.h>
void main(void)
Prof. Luiz Gustavo Almeida Martins Pg.: 34/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
int i = 1, soma = 0;
do
{
soma += i;
i++;
} while (i <= 10)
printf(A soma dos nmeros inteiros de 1 a 10 %d, soma);
getchar();
}
O uso deste comando indicado para os casos onde um conjunto de instrues precisa ser
executado pelo menos uma vez e, ento, repetido condicionalmente.
9.3. COMANDO FOR
O comando for utilizado quando se deseja executar instrues repetidas que envolvam o
incremento/decremento das variveis de controle do loop (ex: leitura e/ou manipulao de
vetores e matrizes). Sua sintaxe geral :
for (inicializao ; condio ; incremento)
{
bloco_comandos;
}
Onde:
Inicializao geralmente um comando de atribuio utilizado para determinar a varivel
de controle do loop e seu valor inicial;
Condio uma expresso relacional que determina o critrio de parada do comando for;
Incremento uma expresso aritmtica que define como a varivel de controle se altera a
cada repetio do comando for.
Estas trs sees devem ser separadas por ponto e vrgula (;).
A seqncia de operao do comando for a seguinte:
Inicializao da varivel de controle;
Teste da condio. Se o resultado for diferente de zero (verdadeiro) executa-se o bloco
de comandos;
Incremento da varivel de controle.
O comando for continua a execuo enquanto o resultado do teste for verdadeiro. Assim que a
condio for falsa (igual a zero), a execuo do programa ser desviada para os comandos
subseqentes ao comando for. Um exemplo deste comando apresentado abaixo:
# include <stdio.h>
void main(void)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 35/82
int i, soma=0;
UFU Universidade Federal de Uberlndia Faculdade de Computao
for (i=1; i <= 10; ++i)
soma += i;
printf(A soma dos nmeros inteiros de 1 a 10 %d, soma);
getchar();
}
VARIAES DO COMANDO
Qualquer uma das trs instrues que formam o comando for pode ser omitida, embora os
ponto e vrgulas devam permanecer.
Se o teste for omitido, o loop se tornar infinito, podendo ser interrompido caso seja usado um
comando de desvio (break, return ou goto) no bloco de comandos do for. Veja o exemplo:
# include <stdio.h>
void main(void)
{
char x;
printf(\nDigite quaisquer caracteres ou tecle A para sair:\n);
for (;;)
{
x=getchar(); /* L um caracter */
if (x == A)
break; /* Sai do loop */
}
printf(\nVoc saiu do Loop);
getchar();
}
Quando a parte do incremento omitida, no feita nenhuma alterao na varivel de controle.
Assim, ou o loop ser executado infinitamente, ou esta alterao dever ser feita dentro do bloco
de comandos do for, como no seguinte exemplo:
# include <stdio.h>
void main(void)
{
int x;
printf(\nDigite quaisquer numeros ou 123 para sair:\n);
for (x=0; x != 123;)
scanf (%d, &x); /* L um nmero */
printf(\nVoc saiu do Loop);
getchar();
}
O comando for permite que haja argumentos mltiplos nas trs sees. Neste caso, os
argumentos adicionais devero ser separados por vrgula (,), como ilustrado no exemplo:
# include <stdio.h>
void main(void)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 36/82
int x, y;
UFU Universidade Federal de Uberlndia Faculdade de Computao
for (x=0, y=100; x < y; x++, --y)
printf (x = %d e y = %d\n, x, y);
printf(Estes foram os valores de x e y enquanto x < y);
getchar();
}
Por fim, tanto a inicializao quanto o incremento podem estar fora dos parnteses de
controle do for, como no exemplo:
# include <stdio.h>
void main(void)
{
int x = 0;
for (; x < 10 ;)
{
printf (x = %d \n, x);
x++;
}
getchar();
}
10. COMANDOS DE DESVIO
s vezes, conveniente se controlar a sada de uma estrutura de repetio (for, while ou do -
while), de outro modo alm dos testes condicionais de incio ou fim do mesmo. Para isto pode-se
usar alguns comandos que permitem desviar a execuo normal de um programa. Tais comandos
so apresentados a seguir.
10.1. COMANDO BREAK
O comando break encerra o processamento de estruturas de repetio ou a execuo de um
comando switch.
O exemplo a seguir mostra um programa que faz uso do comando break.
#include <stdio.h>
void main(void)
{
int NRO, X;
char TEXTO[80];
printf(Digite um nmero inteiro ou zero para sair: );
scanf(%d, &NRO);
while (NRO != 0)
{
TEXTO = O nmero primo;
for (X = 2; X < NRO; X++)
{
if (NRO%X == 0)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 37/82
TEXTO = O nmero no primo;
UFU Universidade Federal de Uberlndia Faculdade de Computao
break;
}
}
puts(TEXTO);
scanf(%d, &NRO);
}
}
Quando executado dentro de uma repetio aninhada (uma estrutura de repetio dentro de
outra), o comando interrompe a repetio mais interna, continuando o processamento na
prxima estrutura de repetio mais interna (estrutura superior imediata).
10.2. COMANDO RETURN
O comando return o mecanismo de sada de uma funo, retornando um valor para a
funo que a chamou. Sua sintaxe :
return (expresso_de_retorno);
Onde, expresso_de_retorno corresponde ao valor que ser utilizado no lugar da chamada
da funo.
Se o comando return estiver dentro de uma estrutura de repetio, ele no s sair da estrutura
como tambm da funo onde foi executado. O exemplo abaixo mostra o return dentro da
funo que eleva um nmero ao quadrado.
# include <stdio.h>
double quadrado(double y);
void main(void)
{
double x;
printf (Digite um nmero: \n);
scanf (%lf, &x);
x = quadrado(x);
printf (O quadrado do nmero : %lf, x);
getchar();
}
double quadrado (double y)
{
return (y *= y);
}
O uso dos parnteses em torno da expresso_de_retorno opcional.
10.3. COMANDO CONTINUE
O comando continue pra a seqncia de instrues que est sendo executada (iterao atual),
passando para a prxima iterao, ou seja, voltando para a 1 linha do bloco de comandos do
loop, conforme apresentado no programa-exemplo a seguir.
Prof. Luiz Gustavo Almeida Martins Pg.: 38/82
# include <stdio.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
void main(void)
{
int x;
printf (Digite um nmero inteiro positivo ou <100> para sair: \n);
do
{
scanf (%d, &x);
if (x < 0)
{
printf (O nmero digitado no ser impresso por ser negativo. \n);
continue;
}
printf(O nmero digitado foi %d. \n, x);
} while (x != 100);
printf (O nmero 100 foi digitado.);
}
Neste exemplo, o nmero digitado s ser impresso na tela se for um nmero positivo. Para isto,
foi empregado o comando continue, o qual provoca a interrupo do bloco de comandos e o
retorno ao comando scanf().
10.4. COMANDO GOTO
O comando goto desvia a seqncia de execuo lgica de um programa, ou seja, ele passa
o controle de programa (realiza um salto incondicional) para a linha de comando identificada por
um rtulo (label). O rtulo pode ser qualquer nome que atenda s regras de criao de
identificadores e deve ser declarado na posio para onde se deseja saltar, seguido de dois
pontos (:). Tanto o comando goto quanto o seu rtulo devem estar declarados dentro da
mesma funo.
A sintaxe geral do comando :
goto nome_rotulo



nome_rotulo:
bloco_comandos;
Este comando no necessrio, podendo sempre ser substitudo por outras estruturas de
controle. Inclusive, o seu uso no recomendvel, pois pode tornar o programa ilegvel e
confuso, principalmente se existirem vrias ocorrncias do comando em diferentes partes do
programa.
Existem algumas situaes muito especficas onde este comando pode tornar o cdigo mais fcil
de entender. Um destes casos quando utilizado para abandonar o processamento de uma
estrutura altamente aninhada (vrios loops e ifs), onde o uso do comando goto mais elegante e
rpido que a utilizao de vrios comandos break.
No exemplo apresentado abaixo, se for digitado o nmero 3, o controle do programa ser
desviado para o label sada.
Prof. Luiz Gustavo Almeida Martins Pg.: 39/82
# include <stdio.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
void main(void)
{
int x = 0;
printf (Entre com caracteres ou tecle 3 para sair: \n);
for (;;)
{
x = getchar(); /* L um caracter */
if (x == 3)
goto saida; /* Sai do Loop */
else
putchar(x);
}
saida:
printf(Voc saiu do Loop);
}
10.5. FUNO EXIT()
A funo exit() encontrada na biblioteca padro do C. Sua utilizao limitada, pois provoca o
encerramento imediato de um programa, retornando ao sistema operacional.
Abaixo apresentado um programa que utiliza esta funo.
# include <stdio.h>
void main(void)
{
char resposta;
printf (Digite um texto qualquer ou <S> para sair: \n);
for (;;)
{
resposta = getchar();
if (resposta == S || resposta == s)
exit();
else
putchar(resposta);
}
}
11. ESTRUTURAS DE DADOS COMPOSTAS
11.1. VETORES E MATRIZES
Vetores nada mais so que matrizes unidimensionais. Portanto, a nica diferena na
declarao e manipulao entre vetores e as demais matrizes, a quantidade de dimenses
envolvidas. Estes tipos de estrutura so caracterizados por possurem todos os elementos de
um mesmo tipo de dado.
A sintaxe geral de sua declarao :
Prof. Luiz Gustavo Almeida Martins Pg.: 40/82
tipo_dado nome_variavel [tamanho1] [tamanho2]... [tamanhoN];
UFU Universidade Federal de Uberlndia Faculdade de Computao
sendo:
N o nmero de dimenses da estrutura (no caso de vetor, N = 1);
tamanhoX o tamanho da dimenso X da estrutura nome_variavel.
Esta declarao permite que o compilador C reserve o espao na memria suficientemente
grande para armazenar o nmero de clulas especificadas pelo tamanho de cada dimenso. Isto
, caso o compilador encontre a seguinte declarao:
int NUMEROS [10], MATRIZ [2][2];
ele ir reservar, de maneira contgua, 20 bytes na memria (2 bytes para cada inteiro vezes 10)
para a varivel NUMEROS e 8 bytes (2 x 2 x 2) para a varivel MATRIZ.
A atribuio ou utilizao do valor de uma das clulas de vetores ou matrizes pode ser feita
atravs da sintaxe:
nome_variavel[numerao1] [numerao2]... [numeraoN] = valor;
ou
varivel = nome_variavel[numerao1] [numerao2]... [numeraoN];
sendo:
numeraoX a posio da clula dentro da dimenso X da estrutura nome_variavel.
Na linguagem C, esta numerao comea sempre em zero. Isto significa que, no exemplo
anterior, os dados de NUMEROS sero indexados de 0 a 19, enquanto que MATRIZ possuir 04
valores indexados, respectivamente, pelos pares ordenados (0,0), (0,1), (1,0) e (1,1). Entretanto, o
compilador C no verifica se o ndice usado no programa est dentro dos limites vlidos
(este cuidado deve ser tomado pelo programador). Quando no dada a devida ateno aos
limites de validade para os ndices, corre-se o risco de ter variveis sobrescritas ou do computador
travar.
Assim como as demais variveis, estes tipos de estrutura tambm podem ser inicializados na
declarao, como segue:
int VETOR [5] = {5, 10, 15, 20, 25};
char TEXTO [2] [2] = {a, b, c, d}; /* (0,0) = a; (0,1) = b; (1,0) = c e (1,1) = d */
Quando a estrutura inicializada na declarao, o tamanho de uma das dimenses pode
ser omitida, pois o mesmo ser considerado a partir da quantidade de valores descritos entre
chaves. Assim, a declarao acima poderia ser reescrita da seguinte forma:
int VETOR [] = {5, 10, 15, 20, 25};
char TEXTO [] [2] = {a, b, c, d};
A seguir apresentado um programa-exemplo que utiliza vetores.
#include <stdio.h>
void main (void)
{
int num[100]; /* Declara um vetor de inteiros de 100 posies */
int count=0;
Prof. Luiz Gustavo Almeida Martins Pg.: 41/82
int totalnums;
UFU Universidade Federal de Uberlndia Faculdade de Computao
do
{
printf ("Entre com um nmero no nulo ou digite 0 p/ terminar: ");
scanf ("%d",&num[count]);
count++;
} while ((num[count-1] != 0) && (count < 100));
totalnums=count;
printf ("\nOs nmeros digitados foram:\n");
for (count=0 ; count < totalnums ; count++)
printf (" %d",num[count]);
}
Neste programa, a entrada de nmeros feita at que o usurio digite zero ou entre com 100
nmeros no nulos. Os nmeros so armazenados no vetor num. A cada nmero armazenado, a
varivel count, utilizada como ndice/contador do vetor, incrementada. Ao sair do primeiro loop,
a quantidade de nmeros digitados pelo usurio armazenada na varivel totalnums. Por fim,
todos os nmeros so impressos.
Abaixo dado um exemplo do uso de matriz. Nele, a estrutura MATRIZ preenchida,
seqencialmente, com os nmeros de 1 a 200.
#include <stdio.h>
void main (void)
{
int MATRIZ [20][10];
int i,j,cont;
cont=1;
for (i=0;i<20;i++)
for (j=0;j<10;j++)
{
MATRIZ[i][j]=cont;
cont++;
}
}
Vale lembrar que, tanto a leitura quanto o preenchimento de uma matriz, o ndice mais direita
varia mais rapidamente que o seu antecessor e assim por diante at o ndice mais esquerda.
11.2. REGISTROS
Um registro uma estrutura de dados heterognea, ou seja, formada por uma coleo de
variveis que podem assumir tipos diferentes de dados, inclusive os tipos compostos (vetores,
matrizes e registros). Neste tipo de estrutura, as variveis so agrupadas juntas sob um nico
nome para a convenincia de manipulao.
Prof. Luiz Gustavo Almeida Martins Pg.: 42/82
Um exemplo tradicional um registro de folha de pagamento, onde um empregado descrito por
um conjunto de atributos, tais como: nome, endereo, nmero do seguro social, salrio, etc.
Alguns desses atributos tambm podem ser uma estrutura, tal como o endereo que possui os
atributos: logradouro, nmero, bairro, complemento, etc.
UFU Universidade Federal de Uberlndia Faculdade de Computao
DECLARAO DE REGISTROS
Na linguagem C, um registro declarado atravs da palavra reservada struct. Esta palavra-chave
introduz uma lista de declaraes entre chaves. Um identificador opcional chamado nome da
estrutura (structure tag) pode seguir a palavra struct. Ele d nome ao registro e pode ser
usado como uma abreviatura para a declarao do registro em outras partes do programa.
As variveis de um registro so chamadas de membros do registro. Um membro pode ter o
mesmo nome de uma outra varivel do programa, desde que esta no pertena ao mesmo
registro. Entretanto, por uma questo de clareza, esta prtica no recomendada.
A seguir apresentado um exemplo com a declarao do registro folha de pagamento.
struct FOLHA
{
char NOME[50];
struct END
{
char LOGRADOURO[50];
int NRO;
char BAIRRO[20];
char COMPLEMENTO[20];
} ENDERECO;
long int NRO_SEG;
float SALARIO;
};
Note que, no exemplo acima, dentro do registro FOLHA existe o registro END, o qual foi atribudo
varivel ENDERECO. Isto ocorre porque, como qualquer outra declarao de varivel, aps a
chave de fechamento (}) da lista de membros do registro pode ser declarada a lista de
variveis que recebero este tipo de estrutura.
Exemplo:
struct { ... } x, y, z;
sintaticamente anloga a:
int x, y, z;
no sentido de que cada comando declara x, y e z como variveis do tipo dado e faz com que seja
reservado o espao de memria necessrio ao armazenamento das mesmas.
Uma declarao de registro sem a lista de variveis s descreve o formato da estrutura,
mas no aloca rea de armazenamento. Se o registro tem nome (identificador), este pode ser
usado depois, na definio de ocorrncias do registro, como no exemplo:
struct FOLHA FOLHA_PAGTO;
Prof. Luiz Gustavo Almeida Martins Pg.: 43/82
Esta declarao define a varivel FOLHA_PAGTO como sendo do tipo registro FOLHA.
Normalmente, a declarao do registro feita no incio do programa (declarao global),
enquanto que a declarao das variveis associadas a este tipo de estrutura realizada nas
respectivas funes (declarao local ou argumentos formais).
UFU Universidade Federal de Uberlndia Faculdade de Computao
Durante a declarao de uma varivel do tipo registro, pode-se inicializar os valores dos
membros da varivel. Para isto, basta utilizar o sinal de igual, seguido de um conjunto de
constantes (uma para cada membro, na mesma ordem da declarao do registro) delimitado
por chaves. Um exemplo de inicializao apresentado abaixo:
struct FOLHA FOLHA_PAGTO = {Jos,{Rua x, 13, Pacaembu, Casa B }, 123, 900.00};
MANIPULAO DE MEMBROS DE UM REGISTRO
Um membro de registro referenciado em uma expresso atravs da construo:
varivel_registro.nome_membro
O operador ponto . conecta o nome da varivel do tipo registro e o nome do membro que
ser utilizado na expresso. Abaixo apresentado alguns exemplos de uso deste operador:
printf (O nome do funcionrio %s, FOLHA_PAGTO.NOME);
DESCONTO_IR = FOLHA_PAGTO.SALARIO * 0.25;
scanf (%li, FOLHA_PAGTO.NRO_SEG);
printf (O bairro do funcionrio %s, FOLHA_PAGTO.ENDERECO.BAIRRO);
Como pode ser observado no ltimo exemplo, a referncia de membros de registros
aninhados feita atravs da identificao ordenada dos registros envolvidos, do mais
externo at o mais interno, todos separados por ponto; seguida pelo nome do membro do
registro mais interno que ser utilizado.
Na linguagem C, quando trabalhamos com dois registros do mesmo tipo (mesma estrutura),
podemos copiar os valores de um registro para o outro atravs do comando:
registro1 = registro2;
Este comando copia o registro2 para o registro1, campo a campo.
MATRIZES DE REGISTRO
Um registro como qualquer outro tipo de dado no C. Portanto, podemos criar matrizes de
registros. Para isto, devemos utilizar a seguinte declarao:
struct nome_registro nome_variavel [tamanho1] [tamanho2]... [tamanhoN];
Sendo que, a quantidade de colchetes que sero utilizados na declarao da matriz de registro
corresponde ao nmero de dimenses da matriz.
Exemplo:
void main(void)
{
struct FOLHA FOLHA_PAGTO[100];
int i;
for (i = 0; i < 100; i++)
FOLHA_PAGTO[i].NRO_SEG = i+1;
}
Prof. Luiz Gustavo Almeida Martins Pg.: 44/82
Neste exemplo, ser alocado espao de memria para 100 instncias do registro FOLHA,
associando este espao varivel FOLHA_PAGAMENTO. Alm disso, o NRO_SEG de cada
instncia receber um nmero equivalente ao ndice da instncia +1.
UFU Universidade Federal de Uberlndia Faculdade de Computao
11.3. COMANDO TYPEDEF
O comando typedef define um novo nome (apelido ou sinnimo) para um tipo de
dado/estrutura j existente. Sua forma geral :
typedef tip_dado apelido;
No exemplo abaixo, a palavra inteiro passa a representar o tipo int e, portanto, pode ser utilizada
nas declaraes das variveis deste tipo.
#include <stdio.h>
typedef int inteiro;
void main(void)
{
inteiro NRO;
scanf (%d, &NRO);
printf (O nmero digitado foi %i,, NRO);
}
Este comando muito utilizado para dar nome a tipos complexos, como registros, pois facilita a
utilizao desta estrutura de dados no restante do programa.
Exemplo:
#include <stdio.h>
typedef struct tipo_endereco {
char rua [50];
int numero;
char bairro [20];
char cidade [30];
char sigla_estado [3];
long int CEP;
} tp_endereco;
struct tipo_cadastro {
char nome [50];
long int telefone;
tp_endereco endereco;
};
typedef struct tipo_cadastro cadastro;
void main(void)
{
cadastro ALUNOS;
ALUNOS.nome = Joaquim Manoel;
ALUNOS.endereco.cidade = Uberlndia;
...
}
Prof. Luiz Gustavo Almeida Martins Pg.: 45/82
Observe que no mais necessrio usar a palavra chave struct na declarao das variveis para
os registros tipo_endereco e tipo_cadastro. Agora, basta usar os apelidos tp_endereco e cadastro.
UFU Universidade Federal de Uberlndia Faculdade de Computao
12. STRINGS
12.1. MANIPULAO DE STRINGS
As strings (cadeia de caracteres) so o uso mais comum para os vetores (string um vetor de
chars). importante lembrar que as strings tm o seu ltimo elemento como um '\0' (terminador
nulo). Portanto, o tamanho de uma string composto pelos caracteres digitados mais o terminador
nulo \0. A declarao geral para uma string :
char nome_da_string [tamanho];
A biblioteca padro do C possui diversas funes que manipulam strings. Estas funes so
teis, pois no se pode, por exemplo, igualar duas strings diretamente (string1 =string2;). As
strings devem ser igualadas elemento a elemento.
Quando vamos fazer programas que tratam de string muitas vezes podemos fazer bom proveito
do fato de que uma string termina com '\0' (isto , o nmero inteiro 0). Veja, por exemplo, o
programa abaixo que serve para igualar duas strings (isto , copia os caracteres de uma string
para o vetor da outra):
#include <stdio.h>
void main (void)
{
int count;
char str1[100],str2[100];
scanf(%s,&str1);
for (count=0;str1[count];count++)
str2[count]=str1[count];
str2[count]='\0';
printf(Voc digitou: %s,str2);
}
A condio no for acima baseada no fato de que a string que est sendo copiada termina em
'\0'. Quando o elemento encontrado em str1[count] o '\0', o valor retornado para o teste
condicional falso (zero). Desta forma a expresso que vinha sendo verdadeira (no zero)
continuamente, torna-se falsa.
12.2. FUNES BSICAS DE MANIPULAO DE STRINGS
Abaixo sero apresentadas algumas funes bsicas para manipulao de strings. Com exceo
da funo gets(), as demais funes esto contidas no arquivo de cabealho string.h
GETS()
A funo gets() l uma string do teclado. Sua forma geral :
gets (nome_da_string);
O programa abaixo demonstra o funcionamento da funo gets():
#include <stdio.h>
int main ()
Prof. Luiz Gustavo Almeida Martins Pg.: 46/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
char string[100];
printf ("Digite o seu nome: ");
gets (string);
printf ("\n\n Ola %s",string);
return(0);
}
Repare que vlido passar para a funo printf() o nome da string. Como o primeiro argumento
da funo printf() uma string, tambm vlido fazer:
printf (string); /* Este comando simplesmente imprimir a string.*/
STRCPY()
A funo strcpy() copia a string de origem para a string de destino. Seu funcionamento
semelhante ao do programa exemplo apresentado na Manipulao de Strings. Sua forma geral :
strcpy (string_destino,string_origem);
A seguir apresentamos um exemplo de uso da funo strcpy():
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[100],str2[100],str3[100];
printf ("Entre com uma string: ");
gets (str1);
strcpy (str2,str1); /* Copia str1 em str2 */
strcpy (str3,"Voce digitou a string "); /* Copia "Voce digitou a string" em str3 */
printf ("\n\n%s%s",str3,str2);
return(0);
}
STRCAT()
A funo strcat() concatena (agrega) o contedo da string de origem ao final da string de destino,
permanecendo a string de origem inalterada. Esta funo tem a seguinte forma geral:
strcat (string_destino,string_origem);
Abaixo segue um exemplo da utilizao da funo strcat():
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[100],str2[100];
printf ("Entre com uma string: ");
gets (str1);
strcpy (str2,"Voce digitou a string ");
Prof. Luiz Gustavo Almeida Martins Pg.: 47/82
strcat (str2,str1); /* str2 armazenara' Voce digitou a string + o contedo de str1 */
UFU Universidade Federal de Uberlndia Faculdade de Computao
printf ("\n\n%s",str2);
return(0);
}
STRLEN()
A funo strlen() retorna o comprimento da string fornecida, desconsiderando o terminador
nulo \0. Isto quer dizer que, de fato, o comprimento do vetor da string deve ser o inteiro retornado
pela funo strlen() mais um. A sintaxe geral da funo :
strlen (string);
Abaixo segue um exemplo do seu uso:
#include <stdio.h>
#include <string.h>
int main ()
{
int size;
char str[100];
printf ("Entre com uma string: ");
gets (str);
size=strlen (str);
printf ("\n\nA string que voce digitou tem tamanho %d",size);
return(0);
}
STRCMP()
A funo strcmp() compara as duas strings passadas como argumento. Se elas forem idnticas, a
funo retorna o valor zero. Caso contrrio, a funo retorna um valor diferente de zero. Sua
forma geral :
strcmp (string1,string2);
Um exemplo da sua utilizao apresentado a seguir:
#include <stdio.h>
#include <string.h>
void main (void)
{
char str1[100],str2[100];
printf ("Entre com uma string: ");
gets (str1);
printf ("\n\nEntre com outra string: ");
gets (str2);
if (strcmp(str1,str2))
printf ("\n\nAs duas strings so diferentes.");
else
printf ("\n\nAs duas strings so iguais.");
Prof. Luiz Gustavo Almeida Martins Pg.: 48/82
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
ATOI() E ATOF()
A funo atoi() (abreviatura de alphanumeric to integer) recebe uma cadeia de caracteres que
representa um nmero inteiro em notao decimal e a converte no nmero inteiro correspondente.
Sua forma geral :
var_int = atoi (string);
De forma similar, a funo atof() (abreviatura de alphanumeric to float) recebe uma cadeia de
caracteres que representa um nmero real em notao decimal e a converte no nmero real (do
tipo double) correspondente. Sua sintaxe :
var_double = atof (string);
Um exemplo da sua utilizao apresentado a seguir:
#include <stdio.h>
#include <stdlib.h>
void main (void)
{
char str1[2] = 12, str2[4] = 2.14;
double soma;
soma = atoi (str1) + atof (str2);
printf ("A soma das strings %lf.",soma);
}
Ambas as funes esto declaradas no arquivo de cabealho <stdlib.h>.
12.3. VETORES DE STRINGS
Vetores de strings so matrizes bidimensionais. Isto porque uma string um vetor, portanto,
ao utilizar um vetor de strings estaremos fazendo, na verdade, um vetor de vetores, ou seja, uma
matriz bidimensional do tipo char. Podemos ver a forma geral de um vetor de strings como sendo:
char nome_da_varivel [numero_de_strings][comprimento_das_strings];
Assim, para acessar um nica string, basta usar o primeiro ndice, como apresentado abaixo:
printf( %s , nome_da_varivel [ndice]);
Abaixo apresentado um programa exemplo que l 5 strings e as exibe na tela:
#include <stdio.h>
void main (void)
{
char strings [5][100];
int count;
for (count=0;count<5;count++)
{
printf ("\n\nDigite a string %d: ", count);
gets (strings[count]);
}
Prof. Luiz Gustavo Almeida Martins Pg.: 49/82
printf ("\n\n\nAs strings que voce digitou foram:\n\n");
UFU Universidade Federal de Uberlndia Faculdade de Computao
for (count=0;count<5;count++)
printf ("%s\n",strings[count]);
}
13. FUNES
Funes so as estruturas que permitem ao usurio separar seus programas em blocos de
construo. A principal caracterstica das funes o fato de, uma vez escritas e depuradas
(testadas), elas poderem ser reutilizadas quantas vezes forem necessrias, inclusive por outros
programas.
Na linguagem C, uma funo tem a seguinte forma geral:
tipo_retorno nome_da_funo (declarao_parmetros)
{
corpo_da_funo
}
O tipo_retorno o tipo de varivel que a funo vai retornar. O default o tipo int, ou seja, uma
funo para a qual no se declara o tipo de retorno considerada como retornando um inteiro.
A declarao_parmetros uma lista de nomes de variveis separadas por vrgulas que
recebem os valores dos argumentos quando a funo chamada. Ela possui a seguinte forma
geral:
tipo nome1, tipo nome2, ... , tipo nomeN
Note que, o tipo deve ser especificado para cada uma das N variveis de entrada. na
declarao de parmetros que informamos ao compilador quais sero as entradas da funo
(assim como informamos a sada no tipo_retorno). Cada varivel descrita na
declarao_parmetros ser tratada como uma varivel local da funo. Quando uma funo
no tiver argumentos de entrada, a lista de parmetros ser vazia. Entretanto, os parnteses da
declarao da funo so obrigatrios.
O corpo_da_funo contm a declarao das variveis locais, bem como a seqncia de
comandos que sero executados, ou seja, o bloco de comandos da funo.
Quando se encontra um comando return, a funo encerrada imediatamente e, se algum
dado informado aps o return, seu valor retornado pela funo. importante lembrar que, o
valor de retorno fornecido tem que ser compatvel com o tipo de retorno declarado para a
funo. Uma funo pode ter mais de um comando return, entretanto, somente um ser
executado por chamada da funo. Isto se torna claro quando pensamos que a funo
terminada quando o programa chega ao primeiro comando return.
Abaixo esto dois exemplos de funes:
/* Programa-Exemplo 1 */
#include <stdio.h>
int square (int a)
{
return (a*a);
}
void main ()
Prof. Luiz Gustavo Almeida Martins Pg.: 50/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
int num;
printf ("Entre com um numero: ");
scanf ("%d",&num);
num=square(num);
printf ("\n\nO seu quadrado vale: %d\n",num);
}

/* Programa-Exemplo 2 */
#include <stdio.h>
int EPar (int a)
{
if (a%2) /* Verifica se a e divisivel por dois */
return 0; /* Retorna 0 se nao for divisivel */
else
return 1; /* Retorna 1 se for divisivel */
}
int main ()
{
int num;
printf ("Entre com numero: ");
scanf ("%d",&num);
if (EPar(num))
printf ("\n\nO numero e par.\n");
else
printf ("\n\nO numero e impar.\n");
return 0;
}
No segundo exemplo, pode ser observado o uso de mais de um comando return na funo.
Como as funes retornam valores, podemos aproveit-los para fazer atribuies e comparaes
condicionais (como parte de uma expresso), ou, ainda, na sada de dados. Mas importante
frisar que, em uma atribuio, as chamadas de funes s podem aparecer no lado direito
dos comandos de atribuio.
Alm disso, se uma funo retorna um valor que no precisa ser aproveitado pelo programa, o
mesmo pode ser despresado. Por exemplo, a funo printf() retorna um inteiro que quase nunca
utilizado, portanto, ele descartado.
13.1. USO DO TIPO VOID EM FUNES
Em ingls, void quer dizer vazio e este o sentido deste tipo de dado. Ele permite a construo
de funes que no retornam nada (procedimentos) e/ou de funes que no tm
argumentos de entrada. A seguir so apresentados alguns exemplos de prottipos de funes
que no retornam nada e/ou no possuem argumentos formais:
void nome_da_funo (declarao_parmetros); /* Sem retorno */
tipo_retorno nome_da_funo (void); /* Sem argumentos de entrada */
Prof. Luiz Gustavo Almeida Martins Pg.: 51/82
void nome_da_funo (void); /* Sem argumentos formais e retorno */
UFU Universidade Federal de Uberlndia Faculdade de Computao
Numa funo sem retorno, o uso do comando return opcional, podendo ser omitido. A seguir
apresentado um exemplo de utilizao do tipo void na declarao de funes:
#include <stdio.h>
void Mensagem (void);
void main (void)
{
Mensagem();
printf ("\tDiga de novo:\n");
Mensagem();
return 0;
}
void Mensagem ()
{
printf ("Ola! Eu estou vivo.\n");
}
Note que na declarao da funo Mensagem(), a palavra void omitida dos parnteses.
A funo main() tambm uma funo e como tal deve ser tratada. Por default, o compilador C
retorna um inteiro para a funo main(). Isto pode ser interessante quando se deseja que o
sistema operacional receba um valor de retorno da execuo do programa. Assim sendo, pode-se
utilizar a seguinte conveno: se o programa retornar zero, significa que ele terminou
normalmente (sem erros); caso contrrio, ou seja, se o programa retornar um valor diferente de
zero, significa que o programa teve um trmino anormal (houve algum erro).
Se no houver interesse no retorno do programa, a funo main() pode ser declarada como
retornando void. Alguns compiladores podem reclamar deste tipo de declarao, dizendo que
main sempre deve retornar um inteiro. Caso isto ocorra, basta fazer main retornar um inteiro.
13.2. CHAMADA DE FUNO
Uma vez que as funes estejam definidas, pode-se usa-las sem se preocupar como elas foram
escritas. Isto o que denominamos chamada de funo. A sintaxe geral da chamada de uma
funo :
nome_funo(lista_valores);
sendo a lista_valores uma lista com os valores que sero atribudos a cada um dos argumentos
formais declarados na funo. Sempre bom lembrar que a quantidade e o tipo dos valores
declarados na lista_valores da chamada da funo devem ser compatveis com aqueles
apresentados na declarao_parmetros da declarao da funo.
Em geral, os argumentos podem ser passados para as funes de duas maneiras, conforme
segue:
PASSAGEM DE PARMETROS POR VALOR
Na passagem de parmetros por valor (ou simplesmente chamada por valor ), os valores
dos argumentos que so passados para a funo so copiados nos parmetros formais
correspondentes. Assim, quaisquer alteraes feitas nestes parmetros formais no tm
efeito nas variveis empregadas na chamada da funo.
Prof. Luiz Gustavo Almeida Martins Pg.: 52/82
O programa abaixo ilustra uma passagem de parmetros por valor
UFU Universidade Federal de Uberlndia Faculdade de Computao
#include <stdio.h>
float sqr (float num);
void main ()
{
float nro,sq;
printf ("Entre com um numero: ");
scanf ("%f",&nro);
sq = sqr(nro);
printf ("\n\nO numero original e: %f\n",nro);
printf ("O seu quadrado vale: %f\n",sq);
}
float sqr (float num)
{
num = num*num;
return num;
}
No exemplo acima, o parmetro formal num da funo sqr() sofre alteraes dentro da funo,
mas a varivel nro da funo main() permanece inalterada.
PASSAGEM DE PARMETROS POR REFERNCIA
Outro tipo de passagem de parmetros para uma funo ocorre quando alteraes nos
parmetros formais, dentro da funo, alteram os valores dos parmetros que foram passados
para a funo. Este tipo de chamada de funo tem o nome de " chamada por referncia" . Este
nome vem do fato de que, neste tipo de chamada, no se passa para a funo os valores das
variveis, mas sim suas referncias (endereo da varivel na memria). A funo usa estas
referncias para alterar os valores das variveis empregadas na chamada da funo.
Neste tipo de chamada, os parmetros formais de uma funo devem ser declarados como
sendo ponteiros (utilizando o operador *). Os ponteiros so a "referncia" que precisamos para
poder alterar a varivel fora da funo. Alm disso, para que estes ponteiros recebam o endereo
de memria das variveis utilizadas na chamada da funo, necessrio colocar o operador &
na frente de cada uma das variveis, como apresentada no exemplo:
#include <stdio.h>
void sqr (float *num);
void main ()
{
float nro;
printf ("Entre com um numero: ");
scanf ("%f",&nro);
printf ("\n\nO numero original e: %f\n",nro);
sqr(&nro);
printf ("O seu quadrado vale: %f\n",nro);
}
void sqr (float *num)
*num = (*num)*(*num);
Prof. Luiz Gustavo Almeida Martins Pg.: 53/82
Neste exemplo, reescrevemos o programa anterior. Nessa nova verso, passado o endereo de
memria da varivel nro para a funo sqr(). Este endereo copiado no ponteiro num. Atravs
UFU Universidade Federal de Uberlndia Faculdade de Computao
do operador * acessamos o contedo apontado por este ponteiro e realizamos a operao
desejada, alterando-o. Neste caso, este contedo nada mais que o valor armazenado em nro,
que, portanto, est sendo modificado.
Note que, uma vez que o valor da funo foi armazenado no endereo de memria de nro, no
necessrio nenhum retorno.
Este tipo de chamada a mesma utilizada pela funo scanf(). Isto porque, esta funo precisa
alterar o valor da varivel passada como parmetro, atribuindo o novo valor digitado pelo usurio.
13.3. RECURSIVIDADE
As funes em C podem chamar umas s outras para executar uma tarefa especfica. Um caso
especial de chamada de funes ocorre quando uma funo chama a si mesma. Este processo
denominado de recurso e a funo chamada funo recursiva.
Na concepo de uma funo recursiva, a primeira providncia definir um critrio de parada
para a recurso, ou seja, determinar quando a funo dever parar de chamar a si mesma. Isto
impede que a recurso se torne infinita e, consequentemente, o programa no tenha fim.
Um bom exemplo de uma funo recursiva a funo que calcule o fatorial de um nmero inteiro:
#include <stdio.h>
unsigned int fat(unsigned int n)
{
if (n > 1 )
return n*fat(n-1);
else
return 1;
}
void main(void)
{
unsigned int NRO;
printf("\n\nDigite um valor inteiro positivo: ");
scanf("%u", &NRO);
printf("\nO fatorial de %d e' %d", NRO, fat(NRO));
}
Neste exemplo, enquanto n > 1, a funo fat() chama a si mesma, cada vez com um valor menor.
O critrio de parada da funo n 1.
Uma funo recursiva quase sempre consome mais memria e tem um processamento
mais demorado que sua verso no recursiva. Isto ocorre porque, a memria consumida na
chamada de uma funo s liberada na concluso da mesma, portanto, o computador aloca
muito mais memria quando a funo recursiva. Entretanto, o cdigo recursivo mais
compacto e, s vezes, mais fcil de entender. Alm disso, h certos algoritmos que so mais
eficientes quando feitos de maneira recursiva. Como exemplo, a construo de alguns tipos de
estruturas de dados abstratos, tais como rvores que at mesmo a sua definio recursiva.
13.4. MATRIZES COMO ARGUMENTO DE FUNES
Prof. Luiz Gustavo Almeida Martins Pg.: 54/82
Quando os argumentos de uma funo so matrizes, tem-se uma exceo conveno de
passagem de parmetros com chamada por valor. Neste caso, apenas o endereo da matriz
UFU Universidade Federal de Uberlndia Faculdade de Computao
passado, no uma cpia da matriz inteira, ou seja, quando se chama uma funo com argumento
matriz, um ponteiro para o primeiro elemento da matriz passado para a funo.
Existem trs maneiras de se declarar um parmetro que ir receber um ponteiro para matriz:
1. Declarando-o como uma matriz;
Tipo_retorno nome_funo (tipo_matriz nome_matriz [dim1] [dim2]... [dimN]);
2. Especificando uma matriz sem dimenso;
Tipo_retorno nome_funo (tipo_matriz nome_matriz [] []... []);
3. Declarando-o como um ponteiro, o que o mais comum.
Tipo_retorno nome_funo (tipo_matriz *nome_matriz [dim2]... [dimN]);
Como exemplo, seja o vetor de inteiros matrx [50] o argumento de uma funo func(). Podemos
declarar func() das seguintes maneiras:
void func (int matrx[50]);
void func (int matrx[]);
void func (int *matrx);
Nos trs exemplos, existir um ponteiro (int *) chamado matrx dentro de func(). Ao passarmos
uma matriz para uma funo, na realidade estamos passando um ponteiro. Neste ponteiro
armazenado o endereo do primeiro elemento da 1 dimenso. Isto significa que no feita uma
cpia, elemento a elemento da matriz. Assim, possvel alterar o valor dos elementos da matriz
dentro da funo.
13.5. ARGUMENTOS PARA A FUNO PRINCIPAL MAIN()
Algumas vezes desejvel passar informaes para um programa no incio de sua execuo.
Nestes casos, estas informaes devem ser passadas para a funo main() via argumentos da
linha de comando e recebidas pela funo atravs de seus parmetros formais. A funo main()
pode ter dois parmetros formais j pr-determinados. Os parmetros argc e argv do ao
programador acesso linha de comando do sistema operacional pela qual o programa foi
chamado. A declarao de uma funo main() com estes parmetros :
tipo_retorno main (int argc,char *argv[]);
O argc (argument count) um inteiro e possui o nmero de palavras digitadas na linha de
comando. Seu valor sempre, pelo menos, igual a 1, pois o nome do programa contado
como sendo o primeiro argumento. Ele tem por finalidade indicar quantos elementos temos
em argv.
O argv (argument values) um ponteiro para uma matriz de strings. Cada string desta matriz
um dos parmetros da linha de comando, separados por espaos em branco. O argv[0]
sempre aponta para o nome do programa (que, como j foi dito, considerado o primeiro
argumento).
No exemplo abaixo, foi escrito um programa chamado data que faz uso dos parmentros argv e
argc. Este programa dever receber da linha de comando os inteiros correspondentes ao dia, ms
e ano, no formato abreviado, e imprimi-la por extenso.
#include <stdio.h>
Prof. Luiz Gustavo Almeida Martins Pg.: 55/82
#include <stdlib.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
void main(int argc, char *argv[])
{
int ms;
char *nm_mes[] = {"Janeiro", "Fevereiro", "Maro", "Abril", "Maio", "Junho", "Julho",
"Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"};

/* O if abaixo testa se o numero de parametros fornecidos est correto:
1 - nome do programa; 2 - dia; 3 - ms; e 4 - ano */
if(argc == 4)
{
/* argv contm strings. A string referente ao ms deve ser transformada em
um inteiro. Para isto, utiliza-se a funo atoi() */
mes = atoi (argv[2]);

if (mes < 1 || mes > 12) /* Testa se o ms vlido */
printf("O ms deveria estar dentro do intervalo 1 e 12.");
else
printf("\n%s de %s de 19%s", argv[1], nomemes[mes-1], argv[3]);
}
else
printf("Nmero de parmetros invlido.");
}
Neste exemplo, ao digitar a linha de comando:
data 19 04 1999
o programa apresentar como sada:
19 de abril de 1999
13.6. CONSIDERAES FINAIS
recomendvel implementar funes da maneira mais geral possvel, pois isto facilita a sua
reutilizao e entendimento. Alm disso, sempre que possvel, deve-se evitar o uso variveis
globais nas funes, pois isto dificulta o reaproveitamento da funo por outros programas, bem
como pode causar efeitos colaterais decorrentes da alterao indevida no valor destas variveis
em outras partes do programa.
Por fim, quando um programa deve apresentar um bom desempenho (performance) de
processamento, seria bom implement-lo sem nenhuma (ou com o mnimo de) chamadas a
funes, porque uma chamada a uma funo consome tempo e memria.
14. ARQUIVOS
Prof. Luiz Gustavo Almeida Martins Pg.: 56/82
O sistema de manipulao de arquivos do ANSI C composto por uma srie de funes
interelacionadas, cujos prottipos esto reunidos em stdio.h. Todas estas funes trabalham com
o conceito de "ponteiro de arquivo. Um ponteiro de arquivo aponta para uma estrutura que
contm informaes sobre o arquivo, como o local de um buffer, a posio do caracter corrente
no buffer, se o arquivo est sendo lido ou gravado e se foram encontrados erros ou o fim do
arquivo. Entratanto, o programador no presisa saber os detalhes desta estrutura, pois a sua
UFU Universidade Federal de Uberlndia Faculdade de Computao
declarao j est definida no arquivo de cabealho stdio.h e chamada FILE. Portanto, para se
cirar um ponteiro de arquivo, basta declar-lo atravs da sintaxe:
FILE *fp;
Onde:
FILE o tipo de dado especial, definido como um typedef dentro do arquivo stdio.h;
fp o nome do ponteiro para arquivo.
14.1. ARQUIVOS PR-DEFINIDOS
Na linguagem C, um arquivo um conjunto de dados que pode ser armazenado e/ou obtido desde
um arquivo em disco at um perifrico (ex: teclado ou impressora).
Quando se comea a execuo de um programa, o sistema automaticamente abre alguns
arquivos pr-definidos:
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)
Cada uma destas constantes pode ser utilizada como um ponteiro para FILE, para acessar os
respectivos perifricos associados. Por exemplo:
ch =getc(stdin); /* efetua a leitura de um caracter a partir do teclado */
putc(ch, stdprn); /* imprime o caracter lido na impressora */
14.2. ABERTURA DE ARQUIVOS
A abertura ou criao de um arquivo no C feita atravs da funo fopen(). Ela retorna o ponteiro
de arquivo associado ao arquivo. O formato geral da funo :
fp = fopen( nome_arquivo , modo_abertura );
Onde:
fp o nome do ponteiro para arquivo (ponteiro do tipo FILE);
nome_arquivo uma string que contm o nome do arquivo que ser manipulado. Este
nome dever ser vlido no sistema operacional que estiver sendo utilizado (ex: no DOS os
nomes devem ter no mximo 12 caracteres, incluindo o ponto e a extenso do arquivo);
Prof. Luiz Gustavo Almeida Martins Pg.: 57/82
modo_abertura uma string que determina como o arquivo ser aberto e, portanto,
utilizado. A tabela abaixo mostra os possveis valores para esta string.
UFU Universidade Federal de Uberlndia Faculdade de Computao
VALORES VLIDOS PARA O MODO DE ABERTURA DE ARQUIVOS
Modo Significado
Abre um arquivo texto para leitura. O arquivo deve existir antes de ser aberto. " r"
Abrir um arquivo texto para gravao. Se o arquivo no existir, ele ser criado. Se j
existir, o contedo anterior ser destrudo.
" w"
Abrir um arquivo texto para gravao. Se ele j existir, os dados sero adicionados no
fim do arquivo ("append"). Caso contrrio, um novo arquivo ser criado.
" a"
Abre um arquivo texto para leitura e gravao. O arquivo deve existir e pode ser
modificado.
" r+"
Cria um arquivo texto para leitura e gravao. Se o arquivo existir, o contedo anterior
ser destrudo. Se no existir, ser criado.
" w+"
Abre um arquivo texto para gravao e leitura. Se o arquivo j existir, os dados sero
adicionados no fim do mesmo. Caso contrrio, um novo arquivo ser criado.
" a+"
Abre um arquivo binrio para leitura (similar ao modo "r"). " rb"
Cria um arquivo binrio para escrita (similar ao modo "w"). " wb"
Acrescenta dados ao final do arquivo binrio (similar ao modo "a"). " ab"
Abre um arquivo binrio para leitura e escrita (similar ao modo "r+"). " r+b"
Cria um arquivo binrio para leitura e escrita (similar ao modo "w+") " w+b"
Acrescenta dados ou cria uma arquivo binrio para leitura e escrita (similar ao modo
"a+").
" a+b"
No exemplo abaixo, aberto um arquivo binrio para escrita:
FILE *fp; /* Declarao do ponteiro de arquivo */
fp=fopen ("exemplo.bin","wb"); /* abertura do arquivo se chama exemplo.bin e est
localizado no diretrio corrente */
if (!fp)
printf ("Erro na abertura do arquivo.");
A condio !fp testa se o arquivo foi aberto com sucesso porque, no caso de um erro, a funo
fopen() retorna um ponteiro nulo (NULL).
OBS: A macro NULL definida em stdio.h como \0.
O padro ANSI determina que pelo menos 8 arquivos podem ser abertos simultaneamente.
Entretanto, a maioria dos compiladores permitem muito mais que isso.
14.3. FECHAMENTO DE ARQUIVOS
Quando acabamos de usar um arquivo que abrimos, devemos fech-lo. Para tanto usa-se a
funo fclose(). Esta funo fecha um arquivo que tenha sido aberto atravs da funo fopen().
Sua sintaxe geral :
fclose (fp);
Prof. Luiz Gustavo Almeida Martins Pg.: 58/82
Onde fp o nome do ponteiro para o arquivo (ponteiro do tipo FILE) aberto pela funo fopen().
UFU Universidade Federal de Uberlndia Faculdade de Computao
O no fechamento de um arquivo pode causar vrios tipos de problemas, incluindo perda de
dados, destruio de arquivos e possveis erros intermitentes no programa. Um fechamento de
arquivo com fclose() tambm libera o bloco de controle de arquivo, deixando-o disponvel para
reutilizao.
Fechar um arquivo faz com que qualquer caracter que tenha permanecido no "buffer" associado
ao fluxo de sada seja gravado.
Mas, o que este "buffer"?
Quando se 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 caracter que fossemos gravar, tivssemos que posicionar a cabea de
gravao em um ponto especfico do disco, as gravaes seriam muito lentas. Com o buffer, as
gravaes s sero efetuadas quando houver um volume razovel de informaes a serem
gravadas ou quando o arquivo for fechado.
A funo retorna um valor inteiro igual a zero quando a operao foi bem sucedida. Qualquer
valor diferente indica erro. Geralmente, os erros retornados esto associados no localizao
da unidade de disco ou inexistncia de espao no disco.
Outra forma de fecharmos arquivos atravs da funo exit(). Esta funo fecha todos os
arquivos abertos do programa.
14.4. LEITURA E ESCRITA EM ARQUIVOS
Aps a abertura de um arquivo, possvel ler ou escrever nele utilizando as funes que sero
apresentadas a seguir.
ESCREVENDO CARACTERES EM ARQUIVOS
Existem duas formas equivalentes para escrever caracteres em arquivos: a macro putc() e a
funo fputc(). Estas duas formas so equivalentes e possuem a mesma sintaxe:
putc (ch, fp);
fputc (ch, fp);
Onde:
fp o nome do ponteiro para o arquivo (ponteiro do tipo FILE) aberto pela funo fopen();
ch o caracter a ser escrito no arquivo na posio apontada pelo ponteiro fp.
Resumidamente, a funo grava o caracter ch no arquivo apontado pelo ponteiro fp, avana o
ponteiro de posio no arquivo e retorna o caracter escrito. Se a funo definir um ponteiro de
erro, ser retornado EOF.
O programa a seguir l uma string do teclado e a escreve, caractere por caractere, em um arquivo
em disco (string.txt).
#include <stdio.h>
#include <stdlib.h>
void main(void)
Prof. Luiz Gustavo Almeida Martins Pg.: 59/82
{
UFU Universidade Federal de Uberlndia Faculdade de Computao
FILE *fp;
char string[100];
int i;
fp = fopen("string.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);
}
Aps a execuo deste programa, o arquivo string.txt criado no diretrio corrente e seu o
contedo pode ser acessado atravs de qualquer editor de textos.
LENDO CARACTERES DE ARQUIVOS
Assim como no caso anterior, tambm existem duas formas equivalentes para ler caracteres de
um arquivo: a macro getc() e a funo fgetc(). As duas formas so equivalentes e possuem a
mesma sintaxe:
var = getc (fp);
var = fgetc (fp);
Onde:
fp o nome do ponteiro para o arquivo (ponteiro do tipo FILE) aberto pela funo fopen();
var a varivel (do tipo int ou char) que receber o caracter lido.
Em caso de fim de arquivo ou erro, ser retornado EOF.
O programa abaixo, ilustrando a aplicao da macro getc(), l qualquer arquivo ASCII, informado
como argumento na chamada do programa, e mostra o seu contedo na tela:
/* Programa: imp_txt.c */
# include <stdio.h>
# include <stdlib.h>
void main (int argc, char *argv[])
{
FILE *fp;
char ch;
if (argc != 2)
{
puts (Sintaxe: imp_txt nome_arq_ASCII);
exit(1);
Prof. Luiz Gustavo Almeida Martins Pg.: 60/82
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
if ((fp = fopen(argv[1], r)) == NULL)
{
puts (O arquivo no pode ser aberto);
exit(1);
}
ch = getc(fp) /* L um caracter do arquivo apontado por fp */
printf (\n\n Sada do arquivo %s : \n, argv[1]);
while (ch != EOF)
{
putchar(ch); /* Mostra o caracter na tela */
ch = getc(fp);
}
fclose(fp);
getchar();
}
LENDO STRINGS DE ARQUIVOS
Para se ler uma string num arquivo podemos usar a funo fgets(). Sua sintaxe :
fgets (str, tam, fp);
Onde:
str a varivel que receber a string lida;
tam o tamanho mximo da string que ser lida;
fp o nome do ponteiro para o arquivo aberto, de onde a string ser lida.
Esta 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 a funo gets(). A string resultante sempre terminar com '\0' (por isto somente
tamanho-1 caracteres, no mximo, sero lidos).
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 j visto, 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 seguinte
construo:
fgets (str, tam, stdin);
Sendo:
str a string que se est lendo;
tam o nmero mximo de caracteres que podem ser lidos (tam = tamanho de str - 1). Esta
subtrao se d por causa do caracter \0.
ESCREVENDO STRINGS EM ARQUIVOS
Prof. Luiz Gustavo Almeida Martins Pg.: 61/82
Para se escrever uma string num arquivo podemos usar a funo fputs(). Sua sintaxe :
UFU Universidade Federal de Uberlndia Faculdade de Computao
fputs (str, fp);
A funo fputs() acessa os caracteres da string str (exceto o caracter especial terminador nulo
\0) e grava-os no arquivo de sada apontado pelo ponteiro fp. Ela retorna um valor negativo se
no tiver um ponteiro de erro definido, caso contrrio, retorna EOF.
No programa-exemplo abaixo, uma string lida do teclado e escrita no arquivo demonimando
TESTE. O final do programa ocorrer quando o usurio inserir uma linha em branco.
# include <stdio.h>
# include <stdlib.h>
void main (void)
{
char str[80];
FILE *fp;
fp = fopen(TESTE, w);
if (fp == NULL)
{
printf (O arquivo no pode ser aberto \n);
exit(1);
}
do {
printf (Entre com uma string ou tecle <ENTER> para terminar: \n);
fgets (str, 79, stdin);
fputs (str, fp);
} while (*str != \n);
fclose (fp);
}
LENDO E ESCREVENDO BLOCOS DE DADOS DE ARQUIVOS
Para ler e escrever tipos de dados maiores que um byte, o sistema de arquivo ANSI C fornece
as funes fread() e fwrite(). Essas funes permitem a leitura e a escrita de blocos de qualquer
tipo de dado.
Funo fread()
A sintaxe de chamada funo fread() :
fread (buffer, num_bytes, cont, fp);
Onde:
buffer um ponteiro para uma regio de memria que receber os dados lidos do arquivo;
num_bytes o tamanho (em bytes) de cada dado que ser lido do arquivo;
cont determina a quantidade de elementos (cada um de comprimento num_bytes) que
sero lidos do arquivo;
fp o ponteiro para um arquivo aberto pelo comando fopen().
Prof. Luiz Gustavo Almeida Martins Pg.: 62/82
Assim, a quantidade total de bytes normalmente lidos do arquivo dada pela expresso:
UFU Universidade Federal de Uberlndia Faculdade de Computao
num_bytes * cont
A funo fread() devolve o nmero de elementos efetivamente lidos. Este valor pode ser menor
que cont se o final de arquivo for atingido ou ocorrer algum erro durante a leitura.
Funo fwrite()
A funo fwrite() possui os mesmos argumentos que a funo fread(), contudo, neste caso, os
argumentos possuem significados diferentes. A sintaxe da funo :
fwrite (buffer, num_bytes, cont, fp);
Onde:
buffer um ponteiro para os dados que sero escritos no arquivo;
num_bytes o tamanho (em bytes) de cada dado que ser escrito no arquivo;
cont determina a quantidade de elementos (cada um de comprimento num_bytes) que
sero escritos no arquivo;
fp o ponteiro para um arquivo aberto pelo comando fopen().
A funo fwrite() devolve o nmero de elementos efetivamente escritos. Este valor ser igual a
cont, a menos que ocorra algum erro durante a processo.
Quando o arquivo for aberto para dados binrios, as funes fread() e fwrite() podem ler e
escrever qualquer tipo de dado.
O programa-exemplo abaixo escreve e, em seguida, l um double, um int e um long int em um
arquivo do disco. Note que, neste exemplo, foi utilizado o operador sizeof(). Ele retorna o
tamanho em bytes de uma varivel ou tipo de dado.
# include <stdio.h>
# include <stdlib.h>
void main (void)
{
FILE *fp;
double d = 12.23;
int i = 101;
long int l = 1230232;
if ((fp = fopen(TEST, wb)) = = NULL)
{
printf (O arquivo no pode ser aberto \n);
exit(1);
}
if ((fwrite (&d, sizeof(double), 1, fp)) != 1)
puts(Houve um erro na escrita do arquivo varivel double);
if ((fwrite (&i, sizeof(int), 1, fp)) != 1)
puts(Houve um erro na escrita do arquivo varivel int);
if ((fwrite (&l, sizeof(long int), 1, fp)) != 1)
puts(Houve um erro na escrita do arquivo varivel long int);
Prof. Luiz Gustavo Almeida Martins Pg.: 63/82
rewind(fp); /* Volta para o incio do arquivo */
UFU Universidade Federal de Uberlndia Faculdade de Computao
if ((fread (&d, sizeof(double), 1, fp)) != 1)
puts(Houve um erro na leitura do arquivo varivel double);
if ((fread (&i, sizeof(int), 1, fp)) != 1)
puts(Houve um erro na leitura do arquivo varivel int);
if ((fread (&l, sizeof(long int), 1, fp)) != 1)
puts(Houve um erro na leitura do arquivo varivel long int);
printf (%.3f %d %ld \n, d, i, l);
fclose(fp);
}
Como pode ser observado, o buffer pode ser, e geralmente , simplesmente a memria usada
para armazernar uma varivel (por isso a necessidade de utilizar o operador &).
O uso das funes fread() e fwrite() muito til para os programas que envolvem a leitura e
escrita de tipos de dados definidos pelo usurio, especialmente registros. Por exemplo, para a
varivel folha definida como:
struct f { char nome[80];
float salrio; } folha;
Podemos escrever seu contedo em um arquivo apontado por fp atravs da seguinte sentena:
fwrite (&folha, sizeof(struct f), 1, fp);
FLUXOS PADRO
Os fluxos padro em arquivos permitem ao programador ler e escrever em arquivos da maneira
similar a qual ele l e escreve na tela. Para isto, so utilizadas as funes fscanf() e fprintf(),
respectivamente.
Funo fprintf()
A funo fprintf() funciona como a funo printf(). A diferena que a sada de fprintf() um
arquivo e no a tela do computador. Sua sintaxe :
fprintf (fp, string_controle , lista de argumentos);
Note que, a nica diferena na sintaxe de fprintf() em relao a printf() a especificao do
ponteiro para o arquivo de destino (fp).
Funo fscanf()
A funo fscanf() funciona como a funo scanf(). A diferena que fscanf() l de um arquivo e
no do teclado do computador. Sua sintaxe :
fscanf (fp, string de controle , lista de endereos de memria das variveis);
Novamente, a nica diferena da sintaxe desta funo para a da funo scanf() a especificao
do ponteiro para o arquivo de destino (fp).
Abaixo apresentado um exemplo de utilizao destas funes. Neste programa, so lidos uma
string e um nmero inteiro do teclado, os quais so gravados no arquivo. Em seguida, se l a
string e o nmero inteiro do arquivo e os apresenta na tela.
# include <stdio.h>
Prof. Luiz Gustavo Almeida Martins Pg.: 64/82
# include <stdlib.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
void main(void)
{
FILE *fp;
char str[80];
int t;
if ( !( fp = fopen(TESTE,"w") ) ) /* Abre o arquivo para gravao */
{
printf("Arquivo no pode ser aberto. \n");
exit(1);
}
printf (Entre com uma string e um numero: \n);
fscanf (stdin, %s %d, str, &t); /* L do teclado */
fprintf (fp," %s %d", str, t); /* Escreve no arquivo */
fclose (fp); /* Fecha o arquivo */
if ( !( fp = fopen(TESTE,"r") ) ) /* Abre o arquivo para leitura */
{
printf("Arquivo no pode ser aberto. \n");
exit(1);
}
fscanf (fp,"%s %d", str, &t); /* L do arquivo */
fprintf (stdout, "%s %d", str, t); /* Escreve na tela */
fclose (fp); /* Fecha o arquivo */
}
14.5. REMOO DE ARQUIVOS
Na linguagem C, pode-se apagar arquivos usando a funo remove(). Sua sintaxe :
remove (nm_arquivo);
Sendo:
nm_arquivo: o nome do arquivo a ser removido.
Esta funo retorna zero caso a remoo seja bem sucedida e um valor diferente de zero, caso
contrrio.
Como esta operao no pode ser desfeita, recomendado confirmar, junto ao usurio, a sua
execuo antes da efetiva remoo. Abaixo, apresentado um programa que apaga um arquivo
especificado na linha de comando.
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
void main (int argc, char *argv[])
{
char CONFIRMA;
if (argc != 2)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 65/82
printf (O nome do arquivo no foi informado. \n);
UFU Universidade Federal de Uberlndia Faculdade de Computao
exit(1);
}
printf (Confirma a remoo do arquivo %s (S/N) \?, argv[1]);
scanf(%c, &CONFIRMA);
if ( toupper(CONFIRMA) = = S )
if ( remove(argv[1]) != 0)
{
puts (O arquivo no pode ser apagado.);
exit(1);
}
}
14.6. LIMPEZA DO BUFFER
A funo fflush() usada para esvaziar o contedo de um buffer de sada. Sua sintaxe :
fflush(fp);
Sendo:
fp: um ponteiro de arquivo vlido.
Esta funo escreve o contedo de qualquer dado existente no buffer do arquivo associado a fp.
Se no for informado o ponteiro fp, a funo descarrega todos os arquivos abertos para sada.
Quando a operao realizada com sucesso, a funo retorna zero. Caso contrrio, retorna EOF.
O exemplo abaixo ilustra o uso desta funo:
# include <stdio.h>
# include <string.h>
void main (void)
{
FILE *stream;
static char msg[] = Isto um teste ;
if ( (stream = fopen (ARQ.DAT, w) ) == NULL)
{
printf (O arquivo ARQ.DAT no pode ser aberto. \n);
exit(1);
}
fwrite (msg, strlen(msg), 1, stream);
puts (Pressione qualquer tecla para descarregar o arquivo ARQ.DAT);
getchar();
if ( fflush (stream) == 0 )
puts (O arquivo foi descarregado com sucesso.);
else
puts (O arquivo no pode ser descarregado.);
fclose (stream);
Prof. Luiz Gustavo Almeida Martins Pg.: 66/82
}
UFU Universidade Federal de Uberlndia Faculdade de Computao
14.7. FUNES DE REPOSICIONAMENTO
Toda vez que estamos trabalhando com arquivos, h uma espcie de posio atual no arquivo.
Esta a posio de onde ser lido ou escrito o prximo caractere. Normalmente, num acesso
seqncial, no precisamos mexer nesta posio, pois quando lemos um dado, a posio no
arquivo automaticamente incrementada. Entretanto, num acesso randmico, muitas vezes
necessrio reposicionar o indicador de posio do arquivo para a obteno do dado
desejado.
FUNO REWIND()
A funo rewind() reposiciona o indicador de posio do arquivo (ponteiro) para o incio do
arquivo especificado pelo ponteiro passado como argumento. Sua sintaxe :
rewind(fp);
O uso desta funo provoca o mesmo efeito do fechamento e abertura do arquivo. Entretanto, o
uso desta funo mais eficiente quanto performance.
FUNO FSEEK()
Para se fazer procuras e acessos randmicos em arquivos usa-se a funo fseek(). Ela modifica o
ponteiro de posio do arquivo. Sua sintaxe :
fseek (fp, num_bytes, origem);
Onde:
fp o ponteiro de arquivo retornado por uma chamada fopen();
Num_bytes um inteiro longo que determina o nmero de bytes a partir de origem que
ser a nova posio do ponteiro;
origem uma das macros descritas na tabela abaixo, e que esto definidas no arquivo de
cabealho stdlib.h.
NOMES DAS MACROS UTILIZADAS NA FUNO FSEEK()
Valor Significado Nome
0 Incio do arquivo SEEK_SET
1 Ponto atual no arquivo SEEK_CUR
2 Fim do arquivo SEEK_END
Abaixo apresentado um exemplo de utilizao desta funo:
# include <stdio.h>
# include <stdlib.h>
void main (int argc, char *argv[])
{
FILE *fp;
if (argc != 3)
{
printf (O nome do arquivo e/ou o nmero de bytes no informados. \n);
Prof. Luiz Gustavo Almeida Martins Pg.: 67/82
exit(1);
UFU Universidade Federal de Uberlndia Faculdade de Computao
}
if ( ( fp = fopen(argv[1], r) ) == NULL)
{
printf (Arquivo %s no pode ser aberto \n, argv[1]);
exit(1);
}
if ( fseek (fp, atol(argv[2]), SEEK_SET) )
{
printf (Erro na busca. \n);
exit(1);
}
printf (O %d.o caracter %c \n, (atol(argv[2]) + 1), getc(fp));
fclose(fp);
}
14.8. OUTRAS FUNES
MACRO FEOF()
EOF ("End Of File") indica o fim de um arquivo. Assim, possvel descobrir se o programa
chegou ao final do arquivo atravs da comparao do caracter lido com o identificador EOF,
descrito no arquivo stdio.h. Esta comparao ilustrada no exemplo abaixo:
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
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);
}
Outra forma de descobrir se o fim de arquivo foi atingido atravs do uso da macro feof(). Ela
retorna um valor diferente de zero quando for encontrado o final do arquivo associado ao ponteiro
de arquivo especificado. Caso contrrio, retornar zero. Sua sintaxe :
feof (fp);
Deste modo , podemos reescrever o programa anterior:
#include <stdio.h>
Prof. Luiz Gustavo Almeida Martins Pg.: 68/82
#include <stdlib.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
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( !feof(fp) ) /* Enquanto no chegar ao final do arquivo */
{
c = getc(fp);
printf("%c", c); /* imprime o caracter lido */
}
fclose(fp);
return 0;
}
FUNO CLEARERR()
A funo clearerr() limpa o erro ou sinal de fim de arquivo associado ao ponteiro de arquivo. Esta
funo possui a seguinte sintaxe:
clearerr(fp);
Sendo:
fp um ponteiro de arquivo associado ao arquivo onde fora encontrado EOF ou tenha
ocorrido algum erro.
MACRO FERROR()
A macro ferror() determina se uma operao com arquivo produziu um erro. Ela retorna zero
se nenhum erro ocorreu ou um nmero diferente de zero se houve algum erro durante o acesso
ao arquivo. Sua sintaxe geral :
ferror(fp)
Esta macro muito til quando desejamos verificar se o acesso a um arquivo teve sucesso,
garantindo, assim, 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.
No programa-exemplo a seguir, fazemos uso das macros ferror(), feof() e da funo clearerr().
Este programa l strings do arquivo TESTE e as grava no arquivo TESTE1.
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
Prof. Luiz Gustavo Almeida Martins Pg.: 69/82
FILE *input, *output;
UFU Universidade Federal de Uberlndia Faculdade de Computao
char str [128];
if ( (input = fopen ("TESTE","r")) ==NULL )
{
printf("\nO arquivo TESTE no pode ser aberto! ");
exit(1);
}
else
{
if ( (output = fopen ("TESTE1","w")) ==NULL )
{
printf("\nO arquivo TESTE no pode ser aberto! ");
exit(1);
}
else
{
fgets (str, sizeof(str), input);
while ( !feof (input) )
{
if ( ferror(input) )
{
puts (Erro na leitura do arquivo \a);
clearerr (input);
}

if ( ferror(output) )
{
puts (Erro na gravao do arquivo \a);
clearerr (output);
}

fgets (str, sizeof(str), input);

}
fclose(input);
fclose(output);
}
}
}
FUNO PERROR()
A funo perror() (Print Error) exibe uma mensagem de erro correspondente ao nmero inteiro
equivalente ao cdigo de erro identificado (errno). A mensagem ser exibida na sada padro de
erro definida em stderr .
A sua sintaxe :
Prof. Luiz Gustavo Almeida Martins Pg.: 70/82
perror(str);
UFU Universidade Federal de Uberlndia Faculdade de Computao
Onde:
str uma string que indica em que parte do programa ocorreu o erro.
No exemplo abaixo,
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
FILE *fp;
char string[100];
if((fp = 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, fp);
putc('\n', fp);
if(ferror(fp))
{
perror("Erro na gravacao");
fclose(fp);
exit(1);
}
} while (strlen(string) > 0);
fclose(fp);
}
Prof. Luiz Gustavo Almeida Martins Pg.: 71/82
Como pode ser observado no exemplo acima, normalmente, a funo perror() usada em
conjunto com a macro ferror().
UFU Universidade Federal de Uberlndia Faculdade de Computao
L E I T U R A CO MP L E ME N T A R L C E I T U R A O MP L E ME N T A R
15. PONTEIROS
Sempre que utilizamos a funo scanf() para ler o elemento de um vetor, passamos o endereo
de memria deste elemento. Para isto, como j visto, utilizamos o operador &, o qual retorna o
endereo de memria alocado para uma varivel. Portanto, se v[i] representa o i-simo
elemento do vetor, &v[i] representa o endereo da memria em que esse elemento est
armazenado.
Na verdade, existe uma associao forte entre vetores e ponteiros. Na declarao:
int v[10];
a varivel v, a qual representa o vetor, uma constante que representa seu endereo inicial, ou
seja, v sem indexao aponta para o primeiro elemento do vetor. Portanto, a linguagem C suporta
aritmtica de ponteiros, isto , pode-se somar e subtrair ponteiros, desde que o valor resultante
aponte para a rea reservada para o vetor.
Se p representa um ponteiro para um inteiro, p+1 representa um ponteiro para o prximo inteiro
armazenado na memria. Este incremento equivale a somar 2 bytes (tamanho de um int) no
endereo de memria armazenado no ponteiro p. Com isso, em um vetor temos as seguintes
equivalncias:
v+0 aponta para o 1 elemento do vetor;
v+1 aponta para o 1 elemento do vetor;
v+2 aponta para o 1 elemento do vetor;
...
v+N aponta para o N-simo elemento do vetor;
Portanto, escrever &v[i] equivalente a escrever (v + i). De maneira anloga, escrever v[i]
equivalente a escrever *(v + i). Isto porque, o operador * retorna o valor contido na posio de
memria indicada por (v + i).
No C a declarao de um ponteiro feita pela seguinte sintaxe:
Tipo_dado *nome_variavel[tamanho1][tamanho2]...[tamanhoN];
A seguir apresentado o exemplo de vetores reescrito para utilizar ponteiro.
#include <stdio.h>
#include <conio.h>
void main (void)
{
int *num; /* Declara um ponteiro para valores inteiros */
int count=0;
int totalnums;
clrscr();
do
{
printf ("Entre com um nmero no nulo ou digite 0 p/ terminar: ");
Prof. Luiz Gustavo Almeida Martins Pg.: 72/82
scanf ("%d",num+count);
UFU Universidade Federal de Uberlndia Faculdade de Computao
count++;
} while ((*(num+count-1) != 0) && (count < 100));
totalnums=count-1;
printf ("\nOs nmeros digitados foram:\n");
for (count=0; count <= totalnums; count++)
{
printf (" %d",*num);
num++;
}
}
Apesar da forma indexada ser mais clara, o uso de ponteiros muito importante,
principalmente por possibilitar a alocao dinmica de memria (reservar espao em memria
para as variveis durante a execuo do programa). Apesar disso, tanto ponteiros quanto
alocao dinmica no fazem parte do escopo deste curso.
O C altamente dependente dos ponteiros. Por isso, para ser um bom programador em C
fundamental que se tenha um bom domnio deles.
15.1. COMO FUNCIONAM OS PONTEIROS
O tipo int guardam inteiros. O tipo float guardam nmeros de ponto flutuante. O tipo char
guardam caracteres. Ponteiros guardam endereos de memria. Quando voc anota o
endereo de um colega voc est criando um ponteiro. O ponteiro este seu pedao de papel.
Ele tem anotado um endereo. Qual o sentido disto? Simples. Quando voc anota o endereo
de um colega, depois voc vai usar este endereo para ach-lo. O C funciona assim. Voce anota
o endereo de algo numa varivel ponteiro para depois usar.
Da mesma maneira, uma agenda, onde so guardados endereos de vrios amigos, poderia ser
vista como sendo uma matriz de ponteiros no C.
Um ponteiro tambm tem tipo. Veja: quando voc anota um endereo de um amigo voc o trata
diferente de quando voc anota o endereo de uma firma. Apesar de o endereo dos dois locais
ter o mesmo formato (rua, nmero, bairro, cidade, etc.) eles indicam locais cujos contedos so
diferentes. Ento os dois endereos so ponteiros de tipos diferentes.
No C quando declaramos ponteiros ns informamos ao compilador para que tipo de varivel
vamos apont-lo. Um ponteiro int aponta para um inteiro, isto , guarda o endereo de um inteiro.
15.2. DECLARANDO E UTILIZANDO PONTEIROS
Para declarar um ponteiro temos a seguinte forma geral:
tipo_do_ponteiro *nome_da_varivel;
o operador asterisco (*) que faz o compilador saber que aquela varivel no vai guardar um
valor, mas sim um endereo para aquele tipo especificado. Vamos ver exemplos de declaraes:
int *pt;
char *temp,*pt2;
Prof. Luiz Gustavo Almeida Martins Pg.: 73/82
O primeiro exemplo declara um ponteiro para um inteiro. O segundo declara dois ponteiros para
caracteres. Eles ainda no foram inicializados (como toda varivel do C que apenas declarada).
UFU Universidade Federal de Uberlndia Faculdade de Computao
Isto significa que eles apontam para um lugar indefinido. Este lugar pode estar, por exemplo, na
poro da memria reservada ao sistema operacional do computador. Usar o ponteiro nestas
circunstnicias pode levar a um travamento do micro, ou a algo pior.
O ponteiro deve ser inicializado (apontado para algum lugar conhecido) antes de ser usado! Isto
de suma importncia!
Para atribuir um valor a um ponteiro recm-criado poderamos igual-lo a um valor de memria.
Mas, como saber a posio na memria de uma varivel do nosso programa? Seria muito difcil
saber o endereo de cada varivel que usamos, mesmo porque estes endereos so
determinados pelo compilador na hora da compilao e realocados na execuo. Podemos ento
deixar que o compilador faa este trabalho por ns. Para saber o endereo de uma varivel basta
usar o operador &. Veja o exemplo:
int count=10;
int *pt;
pt=&count;
Criamos um inteiro count com o valor 10 e um apontador para um inteiro pt. A expresso &count
nos d o endereo de memria de count, que armazenado em pt. Note que no alteramos o
valor de count, que continua valendo 10.
Como ns colocamos um endereo em pt, ele est agora "liberado" para ser usado. Podemos, por
exemplo, alterar o valor de count usando pt. Para tanto vamos usar o operador "inverso" do
operador &, ou seja, o operador *. No exemplo acima, uma vez que fizemos pt=&count a
expresso *pt equivalente ao prprio count. Isto significa que, se quisermos mudar o valor de
count para 12, basta fazer *pt=12.
Vamos fazer uma pausa e voltar nossa analogia para ver o que est acontecendo.
Digamos que exista uma firma. Ela como uma varivel que j foi declarada. Voc tem um papel
em branco onde vai anotar o endereo da firma. O papel um ponteiro do tipo firma. Voc ento
liga para a firma e pede o seu endereo, o qual voc vai anotar no papel. Isto equivalente, no C,
a associar o papel firma com o operador &. Ou seja, o operador & aplicado firma equivalente
a voc ligar para a mesma e pedir o endereo. Uma vez de posse do endereo no papel voc
poderia, por exemplo, fazer uma visita firma. No C voc faz uma visita firma aplicando o
operador * ao papel. Uma vez dentro da firma voc pode copiar seu contedo ou modific-lo.
Uma observao importante: apesar do smbolo ser o mesmo, o operador * (multiplicao) no
o mesmo operador que o * (referncia de ponteiros). Para comear o primeiro binrio, e o
segundo unrio pr-fixado.
Aqui vo dois exemplos de usos simples de ponteiros:
#include <stdio.h> /* Exemplo 1 */
int main ()
{
int num,valor;
int *p;
num=55;
p=&num; /* Pega o endereco de num */
valor=*p; /* Valor e igualado a num de uma maneira indireta */
printf ("\n\n%d\n",valor);
Prof. Luiz Gustavo Almeida Martins Pg.: 74/82
printf ("Endereco para onde o ponteiro aponta: %p\n",p);
UFU Universidade Federal de Uberlndia Faculdade de Computao
printf ("Valor da variavel apontada: %d\n",*p);
return(0);
}

#include <stdio.h> /* Exemplo 2 */
int main ()
{
int num,*p;
num=55;
p=&num; /* Pega o endereco de num */
printf ("\nValor inicial: %d\n",num);
*p=100; /* Muda o valor de num de uma maneira indireta */
printf ("\nValor final: %d\n",num);
return(0);
}
No primeiro exemplo, o cdigo %p usado na funo printf() indica funo que ela deve imprimir
um endereo.
Podemos fazer algumas operaes aritmticas com ponteiros. A primeira, e mais simples,
igualar dois ponteiros. Se temos dois ponteiros p1 e p2 podemos igual-los fazendo p1=p2.
Repare que estamos fazendo com que p1 aponte para o mesmo lugar que p2. Se quisermos que
a varivel apontada por p1 tenha o mesmo contedo da varivel apontada por p2 devemos fazer
*p1=*p2. Basicamente, depois que se aprende a usar os dois operadores (& e *) fica fcil
entender operaes com ponteiros.
As prximas operaes, tambm muito usadas, so o incremento e o decremento. Quando
incrementamos um ponteiro ele passa a apontar para o prximo valor do mesmo tipo 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. Esta mais uma razo pela qual o compilador precisa saber o tipo
de um ponteiro: se voc incrementa um ponteiro char * ele anda 1 byte na memria e se voc
incrementa um ponteiro double* ele anda 8 bytes na memria. O decremento funciona
semelhantemente. Supondo que p um ponteiro, as operaes so escritas como:
p++;
p--;
Mais uma vez insisto. Estamos falando de operaes com ponteiros e no de operaes com o
contedo das variveis para as quais eles apontam. Por exemplo, para incrementar o contedo da
varivel apontada pelo ponteiro p, faz-se:
(*p)++;
Outras operaes aritmticas teis so a soma e subtrao de inteiros com ponteiros. Vamos
supor que voc queira incrementar um ponteiro de 15. Basta fazer:
p=p+15; ou p+=15;
E se voc quiser usar o contedo do ponteiro 15 posies adiante:
*(p+15);
Prof. Luiz Gustavo Almeida Martins Pg.: 75/82
A subtrao funciona da mesma maneira. Uma outra operao, s vezes til, a comparao
entre dois ponteiros. Mas que informao recebemos quando comparamos dois ponteiros? Bem,
UFU Universidade Federal de Uberlndia Faculdade de Computao
em primeiro lugar, podemos saber se dois ponteiros so iguais ou diferentes (==e !=). No caso de
operaes do tipo >, <, >=e <=estamos comparando qual ponteiro aponta para uma posio
mais alta na memria. Ento uma comparao entre ponteiros pode nos dizer qual dos dois est
"mais adiante" na memria. A comparao entre dois ponteiros se escreve como a comparao
entre outras duas variveis quaisquer:
p1>p2
H entretanto operaes que voc no pode efetuar num ponteiro. Voc no pode dividir ou
multiplicar ponteiros, adicionar dois ponteiros, adicionar ou subtrair float ou double de ponteiros.
15.3. PONTEIROS E VETORES
VETORES COMO PONTEIROS
Quando voc declara uma matriz da seguinte forma:
tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN];
o compilador C calcula o tamanho, em bytes, necessrio para armazenar esta matriz. Este
tamanho :
tam1 x tam2 x tam3 x ... x tamN x tamanho_do_tipo
O compilador ento aloca este nmero de bytes em um espao livre de memria. O nome da
varivel que voc declarou na verdade um ponteiro para o tipo da varivel da matriz. Este
conceito fundamental. Eis porque: Tendo alocado na memria o espao para a matriz, ele toma
o nome da varivel (que um ponteiro) e aponta para o primeiro elemento da matriz.
Mas a surge a pergunta: ento como que podemos usar a seguinte notao?
nome_da_varivel[ndice]
Isto pode ser facilmente explicado desde que voc entenda que a notao acima absolutamente
equivalente a se fazer:
*(nome_da_varivel+ndice)
Agora podemos entender como que funciona um vetor! Vamos ver o que podemos tirar de
informao deste fato. Fica claro, por exemplo, porque que, no C, a indexao comea com
zero. porque, ao pegarmos o valor do primeiro elemento de um vetor, queremos, de fato,
*nome_da_varivel e ento devemos ter um ndice igual a zero. Ento sabemos que:
*nome_da_varivel equivalente a nome_da_varivel[0]
Outra coisa: apesar de, na maioria dos casos, no fazer muito sentido, poderamos ter ndices
negativos. Estaramos pegando posies de memria antes do vetor. Isto explica tambm porque
o C no verifica a validade dos ndices. Ele no sabe o tamanho do vetor. Ele apenas aloca a
memria, ajusta o ponteiro do nome do vetor para o incio do mesmo e, quando voc usa os
ndices, encontra os elementos requisitados.
Vamos ver agora um dos usos mais importantes dos ponteiros: a varredura sequencial de uma
matriz. Quando temos que varrer todos os elementos de uma matriz de uma forma sequencial,
podemos usar um ponteiro, o qual vamos incrementando. Qual a vantagem? Considere o seguinte
programa para zerar uma matriz:
Prof. Luiz Gustavo Almeida Martins Pg.: 76/82
int main ()
UFU Universidade Federal de Uberlndia Faculdade de Computao
{
float matrx [50][50];
int i,j;
for (i=0;i<50;i++)
for (j=0;j<50;j++)
matrx[i][j]=0.0;
return(0);
}
Podemos reescrev-lo usando ponteiros:
int main ()
{
float matrx [50][50];
float *p;
int count;
p=matrx[0];
for (count=0;count<2500;count++)
{
*p=0.0;
p++;
}
return(0);
}
No primeiro programa, cada vez que se faz matrx[i][j] o programa tem que calcular o
deslocamento para dar ao ponteiro. Ou seja, o programa tem que calcular 2500 deslocamentos.
No segundo programa o nico clculo que deve ser feito o de um incremento de ponteiro. Fazer
2500 incrementos em um ponteiro muito mais rpido que calcular 2500 deslocamentos
completos.
H uma diferena entre o nome de um vetor e um ponteiro que deve ser frisada: um ponteiro
uma varivel, mas o nome de um vetor no uma varivel. Isto significa, que no se consegue
alterar o endereo que apontado pelo "nome do vetor". Seja:
int vetor[10];
int *ponteiro, i;
ponteiro = &i;
/* as operacoes a seguir sao invalidas */
vetor = vetor + 2; /* ERRADO: vetor nao e' variavel */
vetor++; /* ERRADO: vetor nao e' variavel */
vetor = ponteiro; /* ERRADO: vetor nao e' variavel */
Teste as operaes acima no seu compilador. Ele dar uma mensagem de erro. Alguns
compiladores diro que vetor no um Lvalue ("Left value"). Isto significa que, um smbolo que
pode ser colocado do lado esquerdo de uma expresso de atribuio, ou seja, uma varivel.
Outros compiladores diro que tem-se "incompatible types in assignment", tipos incompatveis
em uma atribuio.
Prof. Luiz Gustavo Almeida Martins Pg.: 77/82
/* as operacoes abaixo sao validas */
UFU Universidade Federal de Uberlndia Faculdade de Computao
ponteiro = vetor; /* CERTO: ponteiro e' variavel */
ponteiro = vetor+2; /* CERTO: ponteiro e' variavel */
PONTEIROS COMO VETORES
Sabemos agora que, na verdade, o nome de um vetor um ponteiro constante. Sabemos tambm
que podemos indexar o nome de um vetor. Como consequncia podemos tambm indexar um
ponteiro qualquer. O programa mostrado a seguir funciona perfeitamente:
#include <stdio.h>
int main ()
{
int matrx [10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *p;
p=matrx;
printf ("O terceiro elemento do vetor e: %d",p[2]);
return(0);
}
Podemos ver que p[2] equivale a *(p+2).
ENDEREOS DE ELEMENTOS DE VETORES
Nesta seo vamos apenas ressaltar que a notao
&nome_da_varivel[ndice]
vlida e retorna o endereo do ponto do vetor indexado por ndice. Isto seria equivalente a
nome_da_varivel + indice. interessante notar que, como consequncia, o ponteiro
nome_da_varivel tem o endereo &nome_da_varivel[0], que indica onde na memria est
guardado o valor do primeiro elemento do vetor.
VETORES DE PONTEIROS
Podemos construir vetores de ponteiros como declaramos vetores de qualquer outro tipo. Uma
declarao de um vetor de ponteiros inteiros poderia ser:
int *pmatrx [10];
No caso acima, pmatrx um vetor que armazena 10 ponteiros para inteiros.
15.4. INICIALIZANDO PONTEIROS
Podemos inicializar ponteiros. Vamos ver um caso interessante dessa inicializao de ponteiros
com strings.
Precisamos, para isto, entender como o C trata as strings constantes. Toda string que o
programador insere no programa colocada num banco de strings que o compilador cria. No local
onde est uma string no programa, o compilador coloca o endereo do incio daquela string (que
est no banco de strings). por isto que podemos usar strcpy() do seguinte modo:
strcpy (string," String constante." );
Prof. Luiz Gustavo Almeida Martins Pg.: 78/82
strcpy() pede dois parmetros do tipo char*. Como o compilador substitui a string "String
constante." pelo seu endereo no banco de strings, tudo est bem para a funo strcpy().
UFU Universidade Federal de Uberlndia Faculdade de Computao
O que isto tem a ver com a inicializao de ponteiros? que, para uma string que vamos usar
vrias vezes, podemos fazer:
char *str1=" String constante." ;
A poderamos, em todo lugar que precisarmos da string, usar a varivel str1. Devemos apenas
tomar cuidado ao usar este ponteiro. Se o alterarmos vamos perder a string. Se o usarmos para
alterar a string podemos facilmente corromper o banco de strings que o compilador criou.
Mais uma vez fica o aviso: ponteiros so poderosos, mas, se usados com descuido, podem ser
uma tima fonte de dores de cabea.
15.5. PONTEIROS PARA PONTEIROS
Um ponteiro para um ponteiro como se voc anotasse o endereo de um papel que tem o
endereo da casa do seu amigo. Podemos declarar um ponteiro para um ponteiro com a seguinte
notao:
tipo_da_varivel **nome_da_varivel;
Algumas consideraes: **nome_da_varivel o contedo final da varivel apontada;
*nome_da_varivel o contedo do ponteiro intermedirio.
No C, podemos declarar vrios nveis de aninhamentos de ponteiros para ponteiros, ou seja,
ponteiros para ponteiros; ponteiros para ponteiros para ponteiros; e assim por diante. Para fazer
isto basta aumentar o nmero de asteriscos na declaraco.
Para acessar o valor desejado apontado por um ponteiro para ponteiro, o operador asterisco deve
ser aplicado duas vezes, como mostrado no exemplo abaixo:
#include <stdio.h>
int main()
{
float fpi = 3.1415, *pf, **ppf;
pf = &fpi; /* pf armazena o endereco de fpi */
ppf = &pf; /* ppf armazena o endereco de pf */
printf("%f", **ppf); /* Imprime o valor de fpi */
printf("%f", *pf); /* Tambem imprime o valor de fpi */
return(0);
}
15.6. CUIDADOS A SEREM TOMADOS NA UTILIZAO DE PONTEIROS
O principal cuidado ao se usar um ponteiro deve ser: saiba sempre para onde o ponteiro est
apontando. Portanto, nunca use um ponteiro que no foi inicializado. Um pequeno programa
que demonstra como no usar um ponteiro:
int main () /* Errado - Nao Execute */
{
int x,*p;
x=13;
*p=x;
Prof. Luiz Gustavo Almeida Martins Pg.: 79/82
return(0);
UFU Universidade Federal de Uberlndia Faculdade de Computao
}
Este programa compilar e rodar. O que acontecer? Ningum sabe. O ponteiro p pode estar
apontando para qualquer lugar. Voc estar gravando o nmero 13 em um lugar desconhecido.
Com um nmero apenas, voc provavelmente no vai ver nenhum defeito. Agora, se voc
comear a gravar nmeros em posies aleatrias no seu computador, no vai demorar muito
para travar o micro (se no acontecer coisa pior).
16. ALOCAO DINMICA
A alocao dinmica permite ao programador alocar memria para variveis quando o programa
est sendo executado. Assim, pode-se definir, por exemplo, um vetor ou uma matriz cujo tamanho
definido em tempo de execuo.
Existem diversas outras funes que so amplamente utilizadas, mas dependentes do ambiente e
compilador. No entanto, o padro ANSI C define apenas quatro funes para o sistema de
alocao dinmica, disponveis no arquivo de cabealho stdlib.h, e descritas a seguir.
16.1. FUNO MALLOC()
A funo malloc() serve para alocar um espao de memria. Sua sintaxe geral :
ptr = malloc (num);
Esta funao aloca na memria o nmero de bytes definido por num. Ela retorna um ponteiro ptr
do tipo void * para o primeiro byte alocado. Este ponteiro pode ser atribudo a qualquer tipo de
ponteiro. Se no houver memria suficiente para a alocao requisitada, a funo retorna um
ponteiro nulo (NULL).
Veja um exemplo de alocao dinmica com malloc():
#include <stdio.h>
#include <stdlib.h> /* Para usar malloc() */
void main (void)
{
int *p;
int a, i;
a = 100;
/* O comando abaixo atribui ao ponteiro p o espao necessrio para guardar a N
inteiros, assim, p agora pode ser tratado como um vetor com 100 posies */
p = (int *) malloc (a*sizeof(int) );
if (!p)
{
printf ("** Erro: Memoria Insuficiente **");
exit;
}
for (i = 0; i < a ; i++)
p[i] = i * i;
}
Prof. Luiz Gustavo Almeida Martins Pg.: 80/82
No exemplo acima, alocada memria suficiente para se armazenar a nmeros inteiros. O
operador sizeof() retorna o nmero de bytes de um inteiro. Ele util para se saber o tamanho de
tipos. O ponteiro void* que malloc() retorna convertido para um int* pelo operador cast e
UFU Universidade Federal de Uberlndia Faculdade de Computao
atribudo a p. O comando seguinte testa se a operao foi bem sucedida. Se no tiver sido, p ter
um valor nulo, portanto, !p ser 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)].
16.2. FUNO CALLOC()
A funo calloc() tambm serve para alocar memria, mas sua sintaxe um pouco diferente:
ptr = calloc (num, size);
Esta funao aloca uma quantidade de memria igual a num * size, ou seja, aloca memria
suficiente para um vetor de num objetos de tamanho size. Assim como no caso anterior, ptr
tambm um ponteiro do tipo void * para o primeiro byte alocado. Se no houver memria
suficiente para alocar a memria requisitada a funo calloc() retorna um ponteiro nulo.
Portanto, o programa anterior pode ser rescrito para realizar a alocao dinmica com calloc():
#include <stdio.h>
#include <stdlib.h> /* Para usar calloc() */
void main (void)
{
int *p;
int a, i;
a = 100;
p=(int *)calloc(a,sizeof(int));
if (!p)
{
printf ("** Erro: Memoria Insuficiente **");
exit;
}
for (i = 0; i < a ; i++)
p[i] = i * i;
}
16.3. FUNO REALLOC()
A funo realloc() serve para redefinir a alocao de memria. Sua sintaxe geral :
ptr = realloc (ptr, num);
Esta funao modifica o tamanho da memria previamente alocada e apontada por ptr para aquele
especificado por num. O valor de num pode ser maior ou menor que o tamanho original. Um
ponteiro para a nova alocao devolvido. Isto ocorre porque realloc() pode precisar mover o
bloco alocado originalmente para aumentar seu tamanho, ou seja, alterar o endereo de memria
dos bytes alocados. Se isso ocorrer, o contedo do bloco antigo copiado no novo bloco, e
nenhuma informao perdida. Se ptr for nulo, aloca num bytes e devolve um ponteiro. Se
num zero, a memria apontada por ptr liberada. Se no houver memria suficiente para a
realocao, um ponteiro nulo devolvido e o bloco original deixado inalterado.
No programa abaixo, a alocao existente no ponteiro p, realizada pela da funo malloc(),
alterada atravs da funo realloc().
Prof. Luiz Gustavo Almeida Martins Pg.: 81/82
#include <stdio.h>
UFU Universidade Federal de Uberlndia Faculdade de Computao
#include <stdlib.h> /* Para usar malloc() e realloc()*/
void main (void) {
int *p;
int a, i;
a = 30;
/* No comando abaixo, p recebe o espao necessrio para guardar 30 N inteiros */
p=(int *)malloc(a*sizeof(int));
if (!p) {
printf ("** Erro: Memoria Insuficiente **");
exit; }
for (i=0; i<a ; i++)
p[i] = i*i;
a = 80;
/* O comando abaixo, realocar o tamanho de p a partir do novo valor de a (80) */
p = realloc (p, a*sizeof(int));
for (i=0; i<a ; i++)
p[i] = a*i*(i-6); }
16.4. FUNO FREE()
Quando um espao de memria alocado dinamicamente no mais necessrio, o mesmo deve
ser liberado (desalocado). Para isto, existe a funo free() cuja sintaxe :
free (ptr);
Onde ptr o ponteiro que aponta para o incio da memria alocada.
Atravs deste ponteiro, o programa busca numa "tabela de alocao interna" a quantidade de
bytes que devem ser liberados.
No exemplo abaixo, o espao alocado para p pela funo malloc() liberado pela funo free()
ao final do programa:
#include <stdio.h>
#include <stdlib.h> /* Para usar malloc() e free() */
void main (void) {
int *p;
int a, i;
a = 100;
p = (int *) malloc (a*sizeof(int) );
if (!p) {
printf ("** Erro: Memoria Insuficiente **");
exit; }
for (i = 0; i < a ; i++) {
p[i] = i * i;
printf (\nO elemento %d possui o valor %d., i, p[i]); }
/* O comando abaixo libera o espao de memria alocado para o ponteiro p */
free(p);
Prof. Luiz Gustavo Almeida Martins Pg.: 82/82
}

Você também pode gostar