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

Al mundo !

Vamos escrever nosso programa Al mundo em C. Se voc estiver usando o Linux abra qualquer editor de textos, pode ser o vi, o emacs, o gedit, etc.....e digite o cdigo abaixo:
#include <stdio.h> int main() { printf("Al mundo!"); return(0); }

Grave o programa com o nome de alo.c. Para compilar o programa digite o seguinte na linha de comando: $ gcc alo.c -o alo Para executar o programa: $ alo Lembre-se que para executar o programa: 1. Ele deve estar no PATH 2. Voc deve ter permisso de execuo para o arquivo.

Se voc estiver usando o Windows, provavelmente estar usando um compilador tipo o Turbo C2. Neste tipo de compilador para iniciar um novo programa clique em File/New ou digite ALT+F para abrir o menu File e, neste, escolha a opo New. Digite o cdigo. Para salvar o arquivo fonte clique em File/Save Para compilar o programa, clique em Compile/Make ou digite ALT+C para abrir o menu Compile e, neste, escolha a opo Make. Ao executar o arquivo ser exibida a mensagem Alo mundo! Vamos analisar o cdigo do programa: #include <stdio.h> Esta linha usa a diretiva #include para inserir o arquivo de cabealho stdio.h no seu programa. Os arquivos de cabealho so arquivos que contm definies, macros e funes que so muito utilizadas em todos os programas. Normalmente todo compilador C j vem com muitos arquivos de cabealho, mas voc tambm pode escrever os seus. Os arquivos de cabealho tem a extenso .h int main()

Esta linha indica a definio da funo main. Um programa em C formado por vrias funes. Quando o programa executado main a primeira funo a ser chamada, assim todo programa deve ter uma funo main. { As chaves delimitam um bloco de comandos. printf("Alo mundo!"); A funo printf exibe o contedo do seu argumento na tela. No caso a mensagem Alo mundo !. Esta funo faz parte do arquivo de cabealho stdio.h por isso ele foi includo no programa. O comando terminado com um ; (ponto-e-vrgula). Todo comando em C deve terminar com ; return(0); Este comando indica que a funo main retorna 0 (zero). } A ltima chave fecha o bloco de comandos da funo main. Se voc no entendeu algum dos conceitos ditos acima no se preocupe, apenas aceite e no futuro voc entender o porque disso tudo.

Tipos de dados
A linguagem C possui quatro tipos bsicos de dados: char - usado para armazenar caracteres int - usado para armazenar nmeros inteiros float - usado para armazenar nmeros de ponto flutuante (decimais) de preciso simples double - usado para armazenar nmeros de ponto flutuante de preciso dupla Para definir uma constante usa-se a diretiva #define. Abaixo segue um exemplo do seu uso:

#include <stdio.h> #define IDADE 34 int main() { printf("Sua idade %d anos",IDADE); return(0); }

No exemplo acima, toda ocorrncia da constante IDADE no cdigo do programa ser substituda pelo valor inteiro 34. importante observar que entre #define e IDADE deve haver apenas um espao, e entre IDADE e 34 tambm s deve haver um espao.

Variveis
As variveis devem ser declaradas antes de ser usadas. Para declarar uma varivel basta digitar seu tipo, seguido de espao e de seu nome. No esquea o ponto-e-vrgula encerrando o comando.Exemplo: int idade; float nota; As variveis devem ser declaradas no incio da funo. Exemplo:
#include <stdio.h> int main() { int idade; float nota1, nota2,nota3, nota4; printf("idade = %d",idade); return(0); }

Observe no exemplo acima que permitido declarar mais de uma varivel na mesma linha.

Nomeando constantes e variveis


Para nomear as constantes e variveis siga as seguintes regras:

Os nomes devem comear com um caractere alfabtico O caractere de sublinhado ( _ ) considerado um caractere alfabtico Os nomes podem ser constitudos de caracteres alfabticos ou numricos Os nomes no devem conter caracteres especiais (!, @, #, $, %, , &, *, etc ......) No devem ser utilizadas palavras reservadas da linguagem C que so: int char float short goto for do while switch

unsigned return auto sizeof break

double extern struct union long register typedef static

continue case if else default entry

Por conveo os nomes das constantes devem ser em letras maisculas e os nomes das variveis em letras minsculas.

Operadores aritmticos
OPERADOR + * / % OPERAO soma subtrao multiplicao diviso mdulo (resto da diviso inteira)

Operadores relacionais
OPERADOR > >= < <= == != SIGNIFICADO maior que maior ou igual a menor que menor ou igual a igual a diferente de

Operadores lgicos
OPERADOR && || SIGNIFICADO e ou

Comando de atribuio
= A sada de dados proporcionada pela funo printf. Ela faz parte do arquivo de cabealho stdio.h, assim este arquivo deve ser includo no programa para a utilizao desta funo. Exemplo da utilizao de printf:
#include <stdio.h> int main() { int nr; char letra; nr = 5; letra = 's'; printf("O valor de nr %d\n",nr); printf("O valor de letra %c\n",letra);

return(0); }

Observe que para exibir as variveis utiliza-se os especificadores de formato %d e %c. O caracter de escape \n provoca o avano para a prxima linha. Aps a vrgula esto os argumentos que substituiro os especificadores de formato. Estes argumentos so posicionais. Os especificadores de formato bsicos so: %d => int %c => char %f => float

Entrada de dados
A entrada de dados feita com a funo scanf. Sua sintaxe : scanf("EF",&VARIVEL); onde EF um especificador de formato e VARIVEL varivel onde o dado entrado ser armazenado. Exemplo:
#include <stdio.h> int main() { int nr; char letra[2]; printf("Entre com o valor do nmero :"); scanf("%d",&nr); printf("Entre com a letra :"); scanf("%s",&letra); printf("O nmero %d e a letra %s\n",nr,letra); return(0); }

Inserindo comentrios
Para inserir comentrios em seu cdigo basta coloc-los entre os sinais /* e */ Exemplo:
/* Utilizando a funo scanf() para entrada de dados */ #include <stdio.h> int main() { int nr; char letra[2]; printf("Entre com o valor do nmero :"); scanf("%d",&nr); printf("Entre com a letra :"); /* O especificador de formato %s usado com strings */ scanf("%s",&letra); printf("O nmero %d e a letra %s\n",nr,letra); return(0); }

Bloco de instrues
Todo bloco de instrues em C deve ser delimitado por chaves { Exemplo:
#include <stdio.h> /* o contedo de main() um bloco de instrues * por isso est entre chaves */ int main() { int idade; printf("Entre com a idade :"); scanf("%d",&idade); /* outro bloco de instrues por isso est entre chaves */ if(idade > 21) { printf("Voc j de maior !!!\n"); printf("Voc tem que arrumar um emprego !!!\n"); } else printf("Voc de menor !!!\n"); return(0); }

} .

Desvio condicional
O desvio condicional uma estrutura de fluxo onde o programa analisa uma condio e:

caso esta condio seja verdadeira executa alguns comandos caso esta condio seja falsa executa outros comandos

Em C esta estrutura representada pelo comando if, cuja sintaxe : if (CONDICO) COMANDOS1 else COMANDOS2 Se CONDIO for verdadeira, COMANDOS1 sero executados, caso contrrio, COMANDOS2 sero executados. importante saber como a linguagem C representa um valor verdadeiro ou falso. Para a linguagem C qualquer valor diferente de zero verdadeiro e o valor zero considerado falso. Assim, a anlise:
if (1)

verdadeira. E a anlise:
if (0)

falsa. Este conceito muito usado na linguagem C pois muitas funes retornam valores inteiros. Exemplo do uso de if:
#include <stdio.h> int main() { int idade;

printf("Entre com sua idade :"); scanf("%d",&idade); if(idade > 21) printf("Voc de maior !!!\n"); else { printf("Voc de menor !!!\n"); printf("Tem que amadurecer !!!\n"); } return(0); }

Observe que se o comando nico no h necessidade das chaves para delimitar o bloco de instrues.

Mltipla escolha
A estrutura de mltipla escolha implementada pelo comando switch. Sua sintaxe : switch (VARIVEL) { case VALOR1: COMANDO1; break; case VALOR2: COMANDO2; break; ......................................................... ......................................................... default: COMANDO; break; } O entendimento o seguinte: a VARIVEL comparada com cada VALOR especificado nos cases. Se um VALOR igual a VARIVEL for encontrado, o referido COMANDO executado. Se no houver nenhuma correspondncia com os valores dos cases, o comando de default executado. O comando break deve existir pois, sem ele, os comandos abaixo so executados independente do teste. Exemplo:
#include <stdio.h> int main() { int opcao; printf("1. Pesquisar\n"); printf("2. Comprar\n"); printf("3. Sair\n"); printf("Entre com sua opo :"); scanf("%d",&opcao); printf("\n"); switch (opcao) { case 1: printf("Voc escolheu a opo 1. Pesquisar.\n"); break;

case 2: printf("Voc escolheu a opo 2. Comprar.\n"); break; case 3: printf("Voc escolheu a opo 3. Sair.\n"); break; default:printf("Voc no escolheu nenhuma das trs opes.\n"); break; } return(0); }

Repetio com teste no incio


Esta estrutura representada pelo comando while, cuja sintaxe : while (CONDIO) COMANDOS; A CONDIO avaliada e, caso seja verdadeira, os COMANDOS so executados. Ento, a CONDIO avaliada novamente e, caso seja verdadeira, os COMANDOS so executados de novo. Isto se repete at que a avaliao da CONDIO resulte em falso. A caracterstica importante deste tipo de construo que, caso a CONDIO seja avaliada como falsa j na primeira vez, os COMANDOS no sero executados nenhuma vez. Exemplo:
#include <stdio.h> int main() { int nr; printf("Digite um nmero : (-1 para sair)"); scanf("%d",&nr); while (nr != -1) { printf("Voc digitou %d\n",nr); printf("Digite outro nmero (-1 para sair) :"); scanf("%d",&nr); }; printf("Voc digitou -1 para sair.\n"); return(0); }

Repetio com teste no final


Esta estrutura implementada com o comando do. Sua sintaxe : do COMANDOS while (CONDICO); Os COMANDOS so executados e depois a CONDIO avaliada. Caso, seja verdadeira os COMANDOS so executados novamente e a CONDIO novamente avaliada. Este ciclo continua at que a CONDIO seja falsa. A caracterstica importante deste tipo de construo que os COMANDOS so executados pelo menos uma vez, independente da CONDIO. Observe o cdigo do exemplo da seo anterior usando do:
#include <stdio.h> int main() { int nr; printf("Digite um nmero : (-1 para sair)"); scanf("%d",&nr); do { printf("Voc digitou %d\n",nr); printf("Digite outro nmero (-1 para sair) :"); scanf("%d",&nr); } while (nr != -1); printf("Voc digitou -1 para sair.\n"); return(0); }

Observe que o cdigo no funciona corretamente. Digite -1 logo de incio para encerrar o programa e, mesmo assim as instrues do lao do so executadas. O que no ocorre no cdigo do exemplo da seo anterior.

Repetio com varivel de controle


Esta estrutura implementada pelo comando for, cuja sintaxe : for(INICIALIZAO;CONDIO;INCREMENTO) COMANDOS; o entendimento o seguinte:

A varivel de controle inicializada em INICIALIZAO CONDIO testada e, caso seja verdadeira, os COMANDOS so executados A varivel de controle incrementada de acordo com INCREMENTO CONDIO novamente testada e, caso seja verdadeira, os COMANDOS so executados A varivel de controle incrementada CONDIO novamente testada e, caso seja verdadeira, os COMANDOS so executados O ciclo continua at que CONDIO seja falsa

Exemplo:
#include int main() { int contador; printf("Exibindo os nmeros de 1 at 50\n"); for(contador=1;contador < 51;contador = contador + 1) { printf("%d ",contador); } printf("\n"); return(0); }

Linguagem C - tipos de dados


O C tem 5 tipos bsicos: char, int, float, void, double. Destes no vimos ainda os dois ltimos: O double o ponto flutuante duplo e pode ser visto como um ponto flutuante com muito mais preciso. O void o tipo vazio, ou um "tipo sem tipo". A aplicao deste "tipo" ser vista posteriormente. Para cada um dos tipos de variveis existem os modificadores de tipo. Os modificadores de tipo do C so quatro: signed, unsigned, long e short. Ao float no se pode aplicar nenhum e ao double pode-se aplicar apenas o long. Os quatro modificadores podem ser aplicados a inteiros. A inteno que short e long devam prover tamanhos diferentes de inteiros onde isto for prtico. Inteiros menores (short) ou maiores (long). int normalmente ter o tamanho natural para uma determinada mquina. Assim, numa mquina de 16 bits, int provavelmente ter 16 bits. Numa mquina de 32, int dever ter 32 bits. Na verdade, cada compilador livre para escolher tamanhos adequados para o seu prprio hardware, com a nica restrio de que shorts ints e ints devem ocupar pelo menos 16 bits, longs ints pelo menos 32 bits, e short int no pode ser maior que int, que 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. A seguir 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():

Tipo char unsigned char signed char int unsigned int signed int short int unsigned short int signed short int long int signed long int unsigned long int float double long double

Num de bits 8 8 8 16 16 16 16 16 16 32 32 32 32 64 80

Formato para leitura com scanf %c %c %c %i %u %i %hi %hu %hi %li %li %lu %f %lf %Lf

Intervalo Inicio -128 0 -128 -32.768 0 -32.768 -32.768 0 -32.768 -2.147.483.648 -2.147.483.648 0 3,4E-38 1,7E-308 3,4E-4932 Fim 127 255 127 32.767 65.535 32.767 32.767 65.535 32.767 2.147.483.647 2.147.483.647 4.294.967.295 3.4E+38 1,7E+308 3,4E+4932

O tipo long double o tipo de ponto flutuante com maior preciso. 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.

1. Variveis
Abaixo segue uma tabela com os tipos bsicos de variveis usadas na linguagem C.
TIPO VALOR ARMAZENADO nmeros inteiros positivos e negativos caracteres e nmeros inteiros positivos e negativos nmeros em ponto flutuante positivos e negativos com preciso simples nmeros em ponto flutuante positivos e negativos com preciso dupla nmeros inteiros positivos INTERVALO TAMANHO (bytes) 2

int

-32.768 a 32.767

char

-128 a 127

float

3.4E-38 a 3.4E+38

double

-1.7E-308 a 1.7E+308

unsigned int

0 a 65.535

unsigned char

caracteres e nmeros inteiros positivos nmeros inteiros positivos e negativos nmeros inteiros positivos

0 a 255

long int unsigned long int

-2.147.483.648 a 2.147.483.647 0 a 4.292.967.265

4 4

1.1 Determinando o tamanho de uma varivel


Quando voc precisar determinar o tamanho de uma varivel use o operador sizeof. Ele retorna o nmero de bytes de uma varivel. Sua sintaxe :
sizeof(VARIVEL);

onde VARIVEL pode ser uma varivel ou um tipo de dado. Exemplo


/* usando o operador sizeof */ #include <stdio.h> int main() { int nr; printf("A varivel nr um inteiro e tem %d bytes.\n",sizeof(nr)); printf("J o tipo de dado char tem %d bytes.\n",sizeof(char)); return(0); }

1. Variveis
Abaixo segue uma tabela com os tipos bsicos de variveis usadas na linguagem C.
TIPO VALOR ARMAZENADO nmeros inteiros positivos e negativos caracteres e nmeros inteiros positivos e negativos nmeros em ponto flutuante positivos e negativos com preciso simples nmeros em ponto flutuante positivos e negativos com INTERVALO TAMANHO (bytes) 2

int

-32.768 a 32.767

char

-128 a 127

float

3.4E-38 a 3.4E+38

double

-1.7E-308 a 1.7E+308

preciso dupla unsigned int unsigned char nmeros inteiros positivos caracteres e nmeros inteiros positivos nmeros inteiros positivos e negativos nmeros inteiros positivos 0 a 65.535 0 a 255 2 1

long int unsigned long int

-2.147.483.648 a 2.147.483.647 0 a 4.292.967.265

4 4

1.1 Determinando o tamanho de uma varivel


Quando voc precisar determinar o tamanho de uma varivel use o operador sizeof. Ele retorna o nmero de bytes de uma varivel. Sua sintaxe :
sizeof(VARIVEL);

onde VARIVEL pode ser uma varivel ou um tipo de dado. Exemplo


/* usando o operador sizeof */ #include <stdio.h> int main() { int nr; printf("A varivel nr um inteiro e tem %d bytes.\n",sizeof(nr)); printf("J o tipo de dado char tem %d bytes.\n",sizeof(char)); return(0); }

2. Register
Uma vriavel do tipo register, sempre que possvel, armazenada dentro dos registradores, aumentando a performance do programa. Voc dever us-las com as variveis que seu programa dever acessar repetidamente como as variveis controladoras de lao. Exemplo:
int main() { register int contador; ....................... ....................... ....................... }

3. Interrompendo um lao
Para interromper um lao, seja ele um lao for ou um lao while, voc pode usar os comandos continue e break. O comando continue interrompe o lao e continua na prxima iterao. O comando break interrompe o lao e continua na prxima instruo de programa aps o lao.

4. printf

4.1 Especificadores de formato


ESPECIFICADOR %d %o %x inteiro em formato hexadecimal %X %u %ld %f %c %e float em formato exponencial %E %g %G %s %p %n float. C escolhe melhor maneira de exibio entre normal e exponencial string endereo de um ponteiro quantos caracteres a funo printf exibiu unsigned int long int float char inteiro inteiro em formato octal VALOR

4.2 Exibindo o sinal de positivo ou negativo antes de um nmero


Por padro o sinal de subtrao precede um nmero negativo. Para que o sinal de adio preceda um nmero positivo inclua um sinal de adio logo aps o % no especificador de formato. Exemplo:
#include <stdio.h> int main() { int nr_pos,nr_neg; nr_pos = 3; nr_neg = -3; printf("nr_pos = %+d\n",nr_pos); printf("nr_neg = %d\n",nr_neg); return(0); }

4.3 Formatando valores inteiros


SINTAXE printf (" %5d ",valor); printf(" %05d ",valor); #%o #%x exibe um valor hexadecimal precedido de 0x #%X EFEITO exibe valor com um mnimo de 5 caracteres exibe valor com um mnimo de 5 caracteres precedendo-o com zeros exibe um valor octal precedido de 0 (zero)

4.4 Formatando valores float


printf(" %5.3f ", valor); /* Exibe valor com um mnimo de 5 caracteres e com 3 dgitos a direita do ponto decimal */

4.5 Justificando esquerda


Por padro, printf justifica o texto direita. Para justificar esquerda coloque um sinal de subtrao aps o %. Exemplo:
#include <stdio.h> int main() {

int valor = 1; printf("Justificado a direita => %5d\n",valor);

printf("Justificado a esquerda => %-5d\n",valor); return(0); }

4.6 Quebrando uma string em duas linhas


#include <stdio.h> int main() { printf("Esta string muito grande e por isso foi\ quebrada em mais de uma linha. Para fazer isso voc\ deve usar o sinal de barra invertida."); return(0); }

4.7 Caracteres de escape


CARACTERE \a \b \f \n \r \t \v \\ \' \" \? \nnn aviso sonoro retrocesso avano de formulrio nova linha retorno do carro (sem alimentao de linha) tabulao horizontal tabulao vertical caractere de barra invertida apstrofe aspas interrogao valor ASCII em octal SIGNIFICADO

\xnnn

valor ASCII em hexadecimal

4.8 Verificando quantos caracteres printf exibiu


#include <stdio.h> int main() { int nr_caracteres; printf("Verificando quantos caracteres printf exibiu.%n",&nr_caracteres); printf("\nA frase acima tem %d caracteres.",nr_caracteres); return(0); }

No exemplo acima, o especificador %n coloca o nmero de caracteres exibidos por printf na varivel &nr_caracteres.

4.9 Usando o controlador ANSI para exibir em cores, limpar a tela e posicionar o cursor
Exibindo em cores SEQUNCIA DE ESCAPE
\033[30m \033[31m \033[32m \033[33m \033[34m \033[35m \033[36m \033[37m \033[40m \033[41m \033[42m \033[43m

COR
Cor do primeiro plano preta Cor do primeiro plano vermelha Cor do primeiro plano verde Cor do primeiro plano laranja Cor do primeiro plano azul Cor do primeiro plano magenta Cor do primeiro plano ciano Cor do primeiro plano branca Cor do fundo preta Cor do fundo vermelha Cor do fundo verde Cor do fundo laranja

\033[44m \033[45m \033[46m \033[47m

Cor do fundo azul Cor do fundo magenta Cor do fundo ciano Cor do fundo branca

Exemplo :
#include <stdio.h> int main() { printf("\033[41m"); /* fundo vermelho */ printf("\033[37m"); /* primeiro plano branco */ printf("Exibindo o fundo em vermelho e o primeiro plano em branco.\n"); return(0); }

Posicionando o cursor SEQUNCIA DE ESCAPE


\033[x;yH \033[xA \033[xB \033[yC \033[yD \033[S \033[U \033[2J \033[K

FUNO
posiciona o cursor na linha x, coluna y move o cursor x linhas para cima move o cursor x linhas para baixo move o cursor y colunas para a direita move o cursor y colunas para a esquerda armazena a posio atual do cursor restaura a posio do cursor limpa a tela limpa a linha atual

Exemplo:
#include <stdio.h> int main() { printf("\033[2J"); /* limpa a tela */ return(0); }

4. printf

4.1 Especificadores de formato


ESPECIFICADOR %d %o %x inteiro em formato hexadecimal %X %u %ld %f %c %e float em formato exponencial %E %g %G %s %p %n float. C escolhe melhor maneira de exibio entre normal e exponencial string endereo de um ponteiro quantos caracteres a funo printf exibiu unsigned int long int float char inteiro inteiro em formato octal VALOR

4.2 Exibindo o sinal de positivo ou negativo antes de um nmero


Por padro o sinal de subtrao precede um nmero negativo. Para que o sinal de adio preceda um nmero positivo inclua um sinal de adio logo aps o % no especificador de formato. Exemplo:
#include <stdio.h> int main()

{ int nr_pos,nr_neg; nr_pos = 3; nr_neg = -3; printf("nr_pos = %+d\n",nr_pos); printf("nr_neg = %d\n",nr_neg); return(0); }

4.3 Formatando valores inteiros


SINTAXE printf (" %5d ",valor); printf(" %05d ",valor); #%o #%x exibe um valor hexadecimal precedido de 0x #%X EFEITO exibe valor com um mnimo de 5 caracteres exibe valor com um mnimo de 5 caracteres precedendo-o com zeros exibe um valor octal precedido de 0 (zero)

4.4 Formatando valores float


printf(" %5.3f ", valor); /* Exibe valor com um mnimo de 5 caracteres e com 3 dgitos a direita do ponto decimal */

4.5 Justificando esquerda


Por padro, printf justifica o texto direita. Para justificar esquerda coloque um sinal de subtrao aps o %. Exemplo:
#include <stdio.h> int main() { int valor = 1; printf("Justificado a direita => %5d\n",valor);

printf("Justificado a esquerda => %-5d\n",valor); return(0); }

4.6 Quebrando uma string em duas linhas


#include <stdio.h>

int main() { printf("Esta string muito grande e por isso foi\ quebrada em mais de uma linha. Para fazer isso voc\ deve usar o sinal de barra invertida."); return(0); }

4.7 Caracteres de escape


CARACTERE \a \b \f \n \r \t \v \\ \' \" \? \nnn \xnnn aviso sonoro retrocesso avano de formulrio nova linha retorno do carro (sem alimentao de linha) tabulao horizontal tabulao vertical caractere de barra invertida apstrofe aspas interrogao valor ASCII em octal valor ASCII em hexadecimal SIGNIFICADO

4.8 Verificando quantos caracteres printf exibiu


#include <stdio.h> int main() { int nr_caracteres; printf("Verificando quantos caracteres printf exibiu.%n",&nr_caracteres);

printf("\nA frase acima tem %d caracteres.",nr_caracteres); return(0); }

No exemplo acima, o especificador %n coloca o nmero de caracteres exibidos por printf na varivel &nr_caracteres.

4.9 Usando o controlador ANSI para exibir em cores, limpar a tela e posicionar o cursor
Exibindo em cores SEQUNCIA DE ESCAPE
\033[30m \033[31m \033[32m \033[33m \033[34m \033[35m \033[36m \033[37m \033[40m \033[41m \033[42m \033[43m \033[44m \033[45m \033[46m \033[47m

COR
Cor do primeiro plano preta Cor do primeiro plano vermelha Cor do primeiro plano verde Cor do primeiro plano laranja Cor do primeiro plano azul Cor do primeiro plano magenta Cor do primeiro plano ciano Cor do primeiro plano branca Cor do fundo preta Cor do fundo vermelha Cor do fundo verde Cor do fundo laranja Cor do fundo azul Cor do fundo magenta Cor do fundo ciano Cor do fundo branca

Exemplo :

#include <stdio.h> int main() { printf("\033[41m"); /* fundo vermelho */ printf("\033[37m"); /* primeiro plano branco */ printf("Exibindo o fundo em vermelho e o primeiro plano em branco.\n"); return(0); }

Posicionando o cursor SEQUNCIA DE ESCAPE


\033[x;yH \033[xA \033[xB \033[yC \033[yD \033[S \033[U \033[2J \033[K

FUNO
posiciona o cursor na linha x, coluna y move o cursor x linhas para cima move o cursor x linhas para baixo move o cursor y colunas para a direita move o cursor y colunas para a esquerda armazena a posio atual do cursor restaura a posio do cursor limpa a tela limpa a linha atual

Exemplo:
#include <stdio.h> int main() { printf("\033[2J"); /* limpa a tela */ return(0); }

4. printf

4.1 Especificadores de formato


ESPECIFICADOR %d inteiro VALOR

%o %x

inteiro em formato octal

inteiro em formato hexadecimal %X %u %ld %f %c %e float em formato exponencial %E %g %G %s %p %n float. C escolhe melhor maneira de exibio entre normal e exponencial string endereo de um ponteiro quantos caracteres a funo printf exibiu unsigned int long int float char

4.2 Exibindo o sinal de positivo ou negativo antes de um nmero


Por padro o sinal de subtrao precede um nmero negativo. Para que o sinal de adio preceda um nmero positivo inclua um sinal de adio logo aps o % no especificador de formato. Exemplo:
#include <stdio.h> int main() { int nr_pos,nr_neg; nr_pos = 3; nr_neg = -3; printf("nr_pos = %+d\n",nr_pos); printf("nr_neg = %d\n",nr_neg); return(0); }

4.3 Formatando valores inteiros


SINTAXE printf (" %5d ",valor); printf(" %05d ",valor); #%o #%x exibe um valor hexadecimal precedido de 0x #%X EFEITO exibe valor com um mnimo de 5 caracteres exibe valor com um mnimo de 5 caracteres precedendo-o com zeros exibe um valor octal precedido de 0 (zero)

4.4 Formatando valores float


printf(" %5.3f ", valor); /* Exibe valor com um mnimo de 5 caracteres e com 3 dgitos a direita do ponto decimal */

4.5 Justificando esquerda


Por padro, printf justifica o texto direita. Para justificar esquerda coloque um sinal de subtrao aps o %. Exemplo:
#include <stdio.h> int main() { int valor = 1; printf("Justificado a direita => %5d\n",valor);

printf("Justificado a esquerda => %-5d\n",valor); return(0); }

4.6 Quebrando uma string em duas linhas


#include <stdio.h> int main() { printf("Esta string muito grande e por isso foi\ quebrada em mais de uma linha. Para fazer isso voc\ deve usar o sinal de barra invertida."); return(0); }

4.7 Caracteres de escape

CARACTERE \a \b \f \n \r \t \v \\ \' \" \? \nnn \xnnn aviso sonoro retrocesso

SIGNIFICADO

avano de formulrio nova linha retorno do carro (sem alimentao de linha) tabulao horizontal tabulao vertical caractere de barra invertida apstrofe aspas interrogao valor ASCII em octal valor ASCII em hexadecimal

4.8 Verificando quantos caracteres printf exibiu


#include <stdio.h> int main() { int nr_caracteres; printf("Verificando quantos caracteres printf exibiu.%n",&nr_caracteres); printf("\nA frase acima tem %d caracteres.",nr_caracteres); return(0); }

No exemplo acima, o especificador %n coloca o nmero de caracteres exibidos por printf na varivel &nr_caracteres.

4.9 Usando o controlador ANSI para exibir em cores, limpar a tela e posicionar o cursor

Exibindo em cores SEQUNCIA DE ESCAPE


\033[30m \033[31m \033[32m \033[33m \033[34m \033[35m \033[36m \033[37m \033[40m \033[41m \033[42m \033[43m \033[44m \033[45m \033[46m \033[47m

COR
Cor do primeiro plano preta Cor do primeiro plano vermelha Cor do primeiro plano verde Cor do primeiro plano laranja Cor do primeiro plano azul Cor do primeiro plano magenta Cor do primeiro plano ciano Cor do primeiro plano branca Cor do fundo preta Cor do fundo vermelha Cor do fundo verde Cor do fundo laranja Cor do fundo azul Cor do fundo magenta Cor do fundo ciano Cor do fundo branca

Exemplo :
#include <stdio.h> int main() { printf("\033[41m"); /* fundo vermelho */ printf("\033[37m"); /* primeiro plano branco */ printf("Exibindo o fundo em vermelho e o primeiro plano em branco.\n"); return(0); }

Posicionando o cursor

SEQUNCIA DE ESCAPE
\033[x;yH \033[xA \033[xB \033[yC \033[yD \033[S \033[U \033[2J \033[K

FUNO
posiciona o cursor na linha x, coluna y move o cursor x linhas para cima move o cursor x linhas para baixo move o cursor y colunas para a direita move o cursor y colunas para a esquerda armazena a posio atual do cursor restaura a posio do cursor limpa a tela limpa a linha atual

Exemplo:
#include <stdio.h> int main() { printf("\033[2J"); /* limpa a tela */ return(0); }

4. printf

4.1 Especificadores de formato


ESPECIFICADOR %d %o %x inteiro em formato hexadecimal %X %u unsigned int inteiro inteiro em formato octal VALOR

%ld %f %c %e

long int float char

float em formato exponencial %E %g %G %s %p %n float. C escolhe melhor maneira de exibio entre normal e exponencial string endereo de um ponteiro quantos caracteres a funo printf exibiu

4.2 Exibindo o sinal de positivo ou negativo antes de um nmero


Por padro o sinal de subtrao precede um nmero negativo. Para que o sinal de adio preceda um nmero positivo inclua um sinal de adio logo aps o % no especificador de formato. Exemplo:
#include <stdio.h> int main() { int nr_pos,nr_neg; nr_pos = 3; nr_neg = -3; printf("nr_pos = %+d\n",nr_pos); printf("nr_neg = %d\n",nr_neg); return(0); }

4.3 Formatando valores inteiros


SINTAXE printf (" %5d ",valor); EFEITO exibe valor com um mnimo de 5 caracteres

printf(" %05d ",valor); #%o #%x

exibe valor com um mnimo de 5 caracteres precedendo-o com zeros exibe um valor octal precedido de 0 (zero)

exibe um valor hexadecimal precedido de 0x #%X

4.4 Formatando valores float


printf(" %5.3f ", valor); /* Exibe valor com um mnimo de 5 caracteres e com 3 dgitos a direita do ponto decimal */

4.5 Justificando esquerda


Por padro, printf justifica o texto direita. Para justificar esquerda coloque um sinal de subtrao aps o %. Exemplo:
#include <stdio.h> int main() { int valor = 1; printf("Justificado a direita => %5d\n",valor);

printf("Justificado a esquerda => %-5d\n",valor); return(0); }

4.6 Quebrando uma string em duas linhas


#include <stdio.h> int main() { printf("Esta string muito grande e por isso foi\ quebrada em mais de uma linha. Para fazer isso voc\ deve usar o sinal de barra invertida."); return(0); }

4.7 Caracteres de escape


CARACTERE \a aviso sonoro SIGNIFICADO

\b \f \n \r \t \v \\ \' \" \? \nnn \xnnn

retrocesso avano de formulrio nova linha retorno do carro (sem alimentao de linha) tabulao horizontal tabulao vertical caractere de barra invertida apstrofe aspas interrogao valor ASCII em octal valor ASCII em hexadecimal

4.8 Verificando quantos caracteres printf exibiu


#include <stdio.h> int main() { int nr_caracteres; printf("Verificando quantos caracteres printf exibiu.%n",&nr_caracteres); printf("\nA frase acima tem %d caracteres.",nr_caracteres); return(0); }

No exemplo acima, o especificador %n coloca o nmero de caracteres exibidos por printf na varivel &nr_caracteres.

4.9 Usando o controlador ANSI para exibir em cores, limpar a tela e posicionar o cursor
Exibindo em cores SEQUNCIA DE ESCAPE COR

\033[30m \033[31m \033[32m \033[33m \033[34m \033[35m \033[36m \033[37m \033[40m \033[41m \033[42m \033[43m \033[44m \033[45m \033[46m \033[47m

Cor do primeiro plano preta Cor do primeiro plano vermelha Cor do primeiro plano verde Cor do primeiro plano laranja Cor do primeiro plano azul Cor do primeiro plano magenta Cor do primeiro plano ciano Cor do primeiro plano branca Cor do fundo preta Cor do fundo vermelha Cor do fundo verde Cor do fundo laranja Cor do fundo azul Cor do fundo magenta Cor do fundo ciano Cor do fundo branca

Exemplo :
#include <stdio.h> int main() { printf("\033[41m"); /* fundo vermelho */ printf("\033[37m"); /* primeiro plano branco */ printf("Exibindo o fundo em vermelho e o primeiro plano em branco.\n"); return(0); }

Posicionando o cursor SEQUNCIA DE ESCAPE FUNO

\033[x;yH \033[xA \033[xB \033[yC \033[yD \033[S \033[U \033[2J \033[K

posiciona o cursor na linha x, coluna y move o cursor x linhas para cima move o cursor x linhas para baixo move o cursor y colunas para a direita move o cursor y colunas para a esquerda armazena a posio atual do cursor restaura a posio do cursor limpa a tela limpa a linha atual

Exemplo:
#include <stdio.h> int main() { printf("\033[2J"); /* limpa a tela */ return(0); }

5. Outros operadores
operador de incremento => ++ contador++ ==> o mesmo que contador = contador + 1 contador++ ==> a varivel contador utiliizada e depois incrementada ++contador ==> a varivel contador incrementada e depois utilizada

operador de decremento => -contador-- ==> o mesmo que contador = contador - 1 contador-- ==> a varivel contador utiliizada e depois decrementada --contador ==> a varivel contador decrementada e depois utilizada

simplificando atribuies de expresso a uma varivel

EXPRESSO NORMAL
total = total + 100 conta = conta - 5 metade = metade / 2

EXPRESSO SIMPLIFICADA
total + = 100 conta - = 5 metade / = 2

operador condicional (CONDIO) ? COMANDO_V : COMANDO_F; CONDIO avaliada. Se for verdadeira, COMANDO_V ser executado. Caso contrrio, COMANDO_F ser executado.

6. strings

6.1 Determinando o tamanho de uma string


Para determinar o tamanho de uma string use a funo strlen( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strlen(string) Exemplo:
/* Determinando o tamanho de uma string usando * a funo strlen() */ #include <stdio.h> #include <string.h> int main() { char string[20]; printf("\n"); printf("Determinando o tamanho de uma string\n"); printf("------------------------------------\n"); printf("\n"); printf("Digite a string :"); scanf("%s",&string); printf("\n"); printf("A string tem %d carateres.\n\n",strlen(string)); return(0); }

6.2 Copiando uma string em outra


Para copiar uma string em outra use a funo strcpy( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strcpy(destino, origem) Exemplo:

/* Copiando uma string em outra usando a * funo strcpy() */ #include <stdio.h> #include <string.h> int main() { char string1[10], string2[10]; printf("\n"); printf("Copiando uma string em outra\n"); printf("----------------------------\n"); printf("\n"); printf("Digite string1 :"); scanf("%s",&string1); printf("\n"); printf("string1 = %s\n",string1); printf("string2 = %s\n",strcpy(string2,string1)); return(0); }

Na prtica, todo contedo de string2 substitudo por string1.

6.3 Unindo duas strings


Para unir duas strings use a funo strcat( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strcat(destino, origem) Exemplo:


/* Unindo duas strings usando a * funo strcat() */ #include <stdio.h> #include <string.h> int main() { char string1[100], string2[10]; printf("\n"); printf("Unindo duas strings\n"); printf("-------------------\n"); printf("\n"); printf("Digite string1 :"); scanf("%s",&string1); printf("\n"); printf("Digite string2 :"); scanf("%s",&string2); printf("\n"); printf("Unindo string1 a string2 : %s\n\n",strcat(string2,string1)); return(0); }

6.4 Anexando caracteres de uma string em outra


Para anexar caracteres de uma string em outra use a funo strncat( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strncat(destino, origem, nr_caracteres)

Exemplo:
/* Anexando caracteres de uma string * em outra usando a funo strncat()*/ #include <stdio.h> #include <string.h> int main() { char string1[20],string2[6]="aeiou"; printf("\n"); printf("Anexando caracteres de uma string em outra\n"); printf("------------------------------------------\n"); printf("Entre com string1 :"); scanf("%s",&string1); printf("\n"); printf("string2 = %s\n\n",string2); printf("string1 + 3 caracteres de string 2 = %s\n",strncat(string1,string2,3)); printf("\n"); return(0); }

6.5 Funo que determina se duas strings so iguais


int streql(char *str1, char *str2) { while((*str1 == *str2) && (*str1)) { str1++; str2++; } return((*str1 == NULL) && (*str2 == NULL)); }

6.6 Convertendo uma string para maisculas


Para converter uma string para maisculas use a funo strupr( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strupr(string) Exemplo:
/* Convertendo uma string em maisculas * usando a funo strupr() */ #include <stdio.h> #include <string.h> int main() { char string[20]; printf("\n"); printf("Convertendo uma string para maisculas\n"); printf("------------------------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("string digitada : %s\n",string);

printf("\n"); printf("Convertendo para maisculas : %s\n",strupr(string)); return(0); }

6.7 Convertendo uma string para minsculas


Para converter uma string para minsculas use a funo strlwr( ). Esta funo faz parte do arquivo de cabealho string.h. Sua sintaxe :

strlwr(string) Exemplo:
/* Convertendo uma string em minsculas * usando a funo strlwr() */ #include <stdio.h> #include <string.h> int main() { char string[20]; printf("\n"); printf("Convertendo uma string para minsculas\n"); printf("------------------------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("string digitada : %s\n",string); printf("\n"); printf("Convertendo para minsculas : %s\n",strlwr(string)); return(0); }

6.8 Localizando a primeira ocorrncia de um caractere numa string


Para isso use a funo strchr( ). Ela faz parte do arquivo de cabealho string.h. Sua sintaxe :

strchr(string, caracter) Este funo retorna um ponteiro para a primeira ocorrncia de "caracter". Caso "caracter" no seja encontrado, ela retornar um ponteiro para o caractere NULL que marca o final da string. Exemplo:
/* Localizando o primeiro caracter numa string * usando a funo strchr()*/ #include <stdio.h> #include <string.h> int main() { char string[30] = "Teste da funo strchr()."; char *ptr; printf("\n%s\n",string); ptr = strchr(string, 's');

if (*ptr) { printf("\n"); printf("A primeira ocorrncia de s na posio %d\n",ptr - string); } else printf("Caractere no encontrado.\n"); return(0); }

6.9 Localizando a ltima ocorrncia de um caractere numa string


Para isso use a funo strrchr( ). Ela faz parte do arquivo de cabealho string.h. Sua sintaxe :

strrchr(string, caracter) Este funo retorna um ponteiro para a ltima ocorrncia de "caracter". Caso "caracter" no seja encontrado, ela retornar um ponteiro para o caractere NULL que marca o final da string. Exemplo:
/* Localizando o ltimo caracter numa string * usando a funo strrchr()*/ #include <stdio.h> #include <string.h> int main() { char string[30] = "Teste da funo strrchr()."; char *ptr; printf("\n%s\n",string); ptr = strrchr(string, 's'); if (*ptr) { printf("\n"); printf("A ltima ocorrncia de s na posio %d\n",ptr - string); } else printf("Caractere no encontrado.\n"); return(0); }

6.10 Funo que conta o nmero de ocorrncias de um caractere numa string


int contachar(char string[], char letra) { int contador, tamanho, ocorrencia = 0; tamanho = strlen(string); for(contador=1;contador <= tamanho;contador++) if(string[contador] == letra) ocorrencia++; return(ocorrencia); }

Abaixo segue um exemplo com a utilizao da funo contachar(). O exemplo considera que ela faz parte do arquivo de cabealho <samfunc.h>:

#include <stdio.h> #include <string.h> #include <samfunc.h> int main() { char *string[20]; char letra[2]; int nr; printf("Testando a funo contachar()\n"); printf("---------------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("Entre com a letra :"); scanf("%s",&letra); nr = contachar(string,letra[0]); printf("\n"); printf("Contando o nmero de ocorrncias : %d\n",nr); return(0); }

6.11 Invertendo uma string utilizando a funo strrev( )


Para inverter o contedo de uma string use a funo strrev( ). Ela faz parte do arquivo de cabaalho string.h. Sua sintaxe :

strrev(string) Exemplo:
/* Invertendo uma string usando a * funo strrev() */ #include <stdio.h> #include <string.h> int main() { char string[20]; printf("\n"); printf("Invertendo uma string\n"); printf("---------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("Invertendo ==> %s",strrev(string)); return(0); }

6.12 Substituindo os caracteres da string por um nico caracter


Para substituir todos os caracteres da string pelo mesmo caracter use a funo strset( ). Ela faz parte do arquivo de cabealho string.h. Sua sintaxe :

strset(string,caracter) Exemplo:

/* Substituindo todos os caracteres da string * pelo mesmo caracter usando a funo strset() */ #include <stdio.h> #include <string.h> int main() { char string[20]; char caracter[2]; printf("\n"); printf("Substituindo os caracteres da string\n"); printf("------------------------------------\n"); printf("\n"); printf("Digite a string :"); scanf("%s",&string); printf("\n"); printf("Caractere :"); scanf("%s",&caracter); printf("\n"); printf("Substituindo ==> %s",strset(string,caracter[0])); return(0); }

6.13 Comparando duas strings


Para comparar duas strings use a funo strcmp( ). Ela faz parte do arquivo de cabealho string.h. Sua sintaxe :

strcmp(string1,string2) Se as strings forem iguais a funo retorna zero, se string1 for maior a funo retorna um valor menor que zero e se string2 for maior a funo retorna um valor maior que zero. Exemplo:
/* Comparando duas strings com a funo strcmp() */ #include <stdio.h> #include <string.h> int main() { char string1[20],string2[20]; int retorno; printf("\n"); printf("Comparando duas strings\n"); printf("-----------------------\n"); printf("\n"); printf("Entre com a primeira string :"); scanf("%s",&string1); printf("\n"); printf("Entre com a segunda string :"); scanf("%s",&string2); printf("\n"); retorno = strcmp(string1,string2); if(retorno == 0) printf("As strings so iguais.\n"); else if(retorno < 0) printf("A string1 , maior.\n"); else

printf("A string2 , maior.\n"); return(0); }

OBSERVAES: 1. A funo strcmp( ) possui uma variante, a funo strncmp( ) que compara os n primeiros caracteres de duas strings. Sua sintaxe : strncmp(string1,string2,nr_caracteres) 2. Existem ainda as funes stricmp( ) e strncmpi( ) que comparam duas strings sem considerar a caixa das letras (maisculas ou minsculas).

6.14 Convertendo strings em nmeros


Para converter strings em nmeros utilize as funes abaixo:

FUNO atof(string) atoi(string) atol(string) strtod(string) strtol(string) float int long int double long

CONVERTE STRINGS EM

Estas funes fazem parte do arquivo de cabealho stdlib.h Exemplo:


/* Convertendo strings em nmeros */ #include <stdio.h> #include <stdlib.h> int main() { char string1[20],string2[20]; printf("\n"); printf("Convertendo strings em nmeros\n"); printf("------------------------------\n"); printf("\n"); printf("Entre com a primeira string :"); scanf("%s",&string1); printf("\n"); printf("Entre com a segunda string :"); scanf("%s",&string2); printf("\n"); printf("string1 + string2 = %f",atof(string1) + atof(string2)); return(0); }

6.15 Duplicando uma string


Para duplicar uma string use a funo strdup( ). Ela est no arquivo de cabealho string.h. Sua sintaxe :

*strdup(string) Exemplo:
/* Duplicando uma string */ #include <stdio.h> #include <string.h> int main() { char string[20]; char *copia; printf("\n"); printf("Duplicando uma string\n"); printf("---------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); copia = strdup(string); printf("string ==> %s\n",string); printf("cpia ==> %s\n",copia); return(0); }

6.16 Localizando uma substring dentro da string


Para localizar uma substring dentro da string use a funo strstr( ). Ela pertence ao arquivo de cabealho string.h e sua sintaxe :

strstr(string,substring) Se a substring existir dentro da string, a funo retornar um ponteiro para a primeira letra da substring, seno retornar NULL. Exemplo:
/* Localizando uma substring dentro de uma string */ #include <stdio.h> #include <string.h> int main() { char string[20],substring[20]; char *extrai; int tamanho; printf("\n"); printf("Localizando uma substring dentro da string\n"); printf("------------------------------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("Entre com a substring :");

scanf("%s",&substring); tamanho = strlen(substring); extrai = strstr(string,substring); printf("\n"); if(extrai) { printf("A string contm a substring.\n"); printf("A substring comea na posio %d.\n",extrai-string); printf("A substring tem %d caracteres.\n",tamanho); } else printf("A string no contm a substring.\n"); return(0); }

6.17 Funo que remove uma substring de dentro de uma string


#include <stdio.h> #include <string.h> char *sstr(char *string, char *substring) { char *extrai; int tamanho,contador; tamanho = strlen(substring); extrai = strstr(string,substring); if(extrai) { for(contador = 0;contador < tamanho; contador++) extrai[contador] = string[(extrai - string) + contador]; extrai[contador] = NULL; return(extrai); } else return(" "); } int main() { char string[20],substring[20]; printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("Entre com a substring :"); scanf("%s",&substring); printf("\n"); printf("substring ==> %s\n",sstr(string,substring)); return(0); }

6.18 Funo que substitui uma subtring por outra


#include <stdio.h> #include <string.h> char *subs_str(char *string, char *substring, char *nova) { char *extrai; int tamanho1,tamanho2,contador;

tamanho1 = strlen(substring); tamanho2 = strlen(nova); if((tamanho1 > tamanho2) || (tamanho2 > tamanho1)) return(" "); else { extrai = strstr(string,substring); if(extrai) { for(contador = 0;contador < tamanho1; contador++) string[(extrai - string) + contador] = nova[contador]; return(string); } else return(" "); } } int main() { char string[20],substring[20],nova[20]; printf("\n"); printf("Entre com a string :"); scanf("%s",&string); printf("\n"); printf("Entre com a substring :"); scanf("%s",&substring); printf("\n"); printf("Entre com a nova substring :"); scanf("%s",&nova); printf("\n"); printf("nova string ==> %s\n",subs_str(string,substring,nova)); return(0); }

6.19 Invertendo uma string sem o uso da funo strrev( )


/* Invertendo uma string */ #include <stdio.h> #include <string.h> int main() { char string[100],invertida[100]; char *caracter; int tamanho,contador; printf("\n"); printf("Invertendo uma string\n"); printf("---------------------\n"); printf("\n"); printf("Entre com a string :"); scanf("%s",&string); tamanho = strlen(string); contador = tamanho; caracter = &string; while(*caracter) {

invertida[(contador - 1)] = *caracter; *(caracter++); contador--; } invertida[tamanho] = NULL; printf("\n"); printf("Invertendo ==> %s\n\n",invertida); return(0); }

7. Caracter

7.1 Verificando se o caracter uma letra


Para fazer esta verificao utilize a macro isalpha( ). Ela faz parte do arquivo de cabealho ctype.h. Sua sintaxe : isalpha(caracter) Exemplo:
/* Verificando se um caracter uma letra * usando a macro isalpha() */ #include <stdio.h> #include <ctype.h> int main() { char caracter; printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (isalpha(caracter)) printf("O caracter uma letra.\n"); else printf("O caracter no uma letra.\n"); return(0); }

7.2 Verificando se o caracter um valor ASCII


Um valor ASCII um valor entre 0 e 127. Para verificar se um caractere um valor ASCII utilize a macro isascii( ) que faz parte do arquivo de cabealho ctype.h. Sua sintaxe :

isascii(caracter) Exemplo :
/* Verificando se um caracter contm um valor ASCII * usando a macro isascii() */ #include <stdio.h> #include <ctype.h> int main() { char caracter;

printf("\n"); printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (isascii(caracter)) printf("O caracter contm o valor ASCII %d.\n",caracter); else printf("O caracter no contm um valor ASCII.\n"); printf("\n"); return(0); }

7.3 Verificando se o caracter um caracter de controle


Um caracter de controle composto pelo pressionamento da tecla control (CTRL) e uma letra ( ^A , ^B, ^C, ...... ^Z ou ^a, ^b, ^c ...... ^z). Para verificar se um caractere de controle use a macro iscntrl( ). Ela faz parte do arquivo de cabealho ctype.h e sua sintaxe : iscntrl(caracter) Exemplo:
/* Verificando se um caracter de controle * usando a macro iscntrl() */ #include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (iscntrl(caracter)) { printf("O caracter digitado um caracter de controle\n"); printf("e equivale ao cdigo ASCII %d.\n",caracter); } else printf("O caracter digitado no um caracter de controle.\n"); printf("\n"); return(0); }

7.4 Verificando se o caracter um dgito


Para verificar se o caracter um dgito use a macro isdigit( ). Ela pertence ao arquivo de cabealho ctype.h e sua sintaxe : isdigit(caracter) Exemplo :
/* Verificando se um caracter um dgito * usando a macro isdigit() */

#include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (isdigit(caracter)) printf("O caracter um dgito.\n"); else printf("O caracter no um dgito.\n"); printf("\n"); return(0); }

7.5 Verificando se o caracter maisculo


Para verificar se o caracter maisculo use a macro isupper( ). Ela pertence ao arquivo de cabealho ctype.h e sua sintaxe : isupper(caractere) Exemplo:
/* Verificando se um caracter maisculo * usando a macro isupper() */ #include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (isupper(caracter)) printf("O caracter maisculo.\n"); else printf("O caracter no um maisculo.\n"); printf("\n"); return(0); }

7.6 Verificando se o caracter minsculo


Para verificar se o caracter minsculo use a macro islower( ). Ela pertence ao arquivo de cabealho ctype.h e sua sintaxe : islower(caractere) Exemplo:
/* Verificando se um caracter minsculo * usando a macro islower() */

#include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter :"); caracter = getchar(); printf("\n"); if (islower(caracter)) printf("O caracter minsculo.\n"); else printf("O caracter no um minsculo.\n"); printf("\n"); return(0); }

7.7 Convertendo um caracter para maisculo


Para executar esta converso voc pode usar a macro _toupper( ) ou a funo toupper( ). As duas esto no arquivo de cabealho ctype.h. A diferena entre as duas que a macro no testa se o caractere a ser convertido um minsculo. Assim, se o caracter no for uma letra minscula a macro far uma converso errada. Se voc tiver certeza que o caractere uma letra minscula use a macro que mais rpida, caso contrrio use a funo. A sintaxe das duas segue abaixo: _toupper(caracter) toupper(caracter) Exemplo :
/* Convertendo um caracter para maisculo */ #include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter minsculo, um dgito ou um smbolo qualquer :"); caracter = getchar(); printf("\n"); printf("Convertendo com a funo toupper( ) ==> %c\n",toupper(caracter)); printf("\n"); printf("Convertendo com a macro _toupper( ) ==> %c\n",_toupper(caracter)); printf("\n"); return(0); }

7.8 Convertendo um caracter para minsculo


Para executar esta converso voc pode usar a macro _tolower( ) ou a funo tolower( ). As duas esto no arquivo de cabealho ctype.h. A diferena entre as duas que a macro no testa se o caractere a ser convertido um maisculo. Assim, se o caracter no for uma letra maiscula a macro far uma converso errada. Se voc tiver certeza que o caractere uma letra maiscula use a macro que mais rpida, caso contrrio use a funo. A sintaxe das duas segue abaixo:

_tolower(caracter) tolower(caracter) Exemplo :


/* Convertendo um caracter para minsculo */ #include <stdio.h> #include <ctype.h> int main() { char caracter; printf("\n"); printf("Digite um caracter maisculo, um dgito ou um smbolo qualquer :"); caracter = getchar(); printf("\n"); printf("Convertendo com a funo tolower( ) ==> %c\n",tolower(caracter)); printf("\n"); printf("Convertendo com a macro _tolower( ) ==> %c\n",_tolower(caracter)); printf("\n"); return(0); }

8. Funes

8.1 Forma geral de uma funo


TIPO NOME(PARMETROS) { CORPO DA FUNO }

Onde:

TIPO o tipo de valor retornado pela funo. Se nada for especificado o compilador considera que ser retornado um valor inteiro. NOME o nome da funo PARMETROS a lista das variveis que recebem os argumentos quando a funo chamada. Deve incluir o tipo e nome de cada varivel. Sua sintaxe :(tipo varivel1, tipo varivel2, ......, tipo
variveln)

CORPO onde esto as instrues da funo

Exemplo:
int soma(int a,int b) { int resultado; resultado = a + b; return(resultado); }

8.2 Variveis em funes


As variveis criadas numa funo so locais, assim sero destrudas aps o trmino da funo.

Caso voc queira manter o valor de uma varivel entre as chamadas a uma funo voc deve declarar esta varivel como static. Exemplo:
/* Mantendo o valor de uma varivel entre as * chamadas de uma funo */ #include <stdio.h> int soma_1(int a); int main() { int nr = 1; printf("Chamando a funo a primeira vez: valor + 1 = %d\n",soma_1(nr)); printf("Chamando a funo pela segunda vez: : valor + 1 = %d\n",soma_1(nr)); printf("Chamando a funo pela terceira vez: : valor + 1 = %d\n",soma_1(nr)); return(0); }

int soma_1(int a) { static int valor = 1; printf("valor = %d\n",valor); valor = valor + a; return(valor); }

Caso uma varivel local a funo tenha o mesmo nome de uma varivel global, a varivel local ser usada e no a global. Exemplo:
/* Entre variveis locais e globais com o mesmo nome * dentro de uma funo, a varivel local escolhida */ #include <stdio.h> int a = 1; /* varivel global */ void exibe(void) { int a = 10; /* varivel local a funo exibe() */ printf("a dentro da funo = %d\n",a); } int main() { printf("\n"); printf("a dentro de main = %d\n",a); exibe(); printf("\n"); return(0); }

BIZ: Evite variveis globais.

8.3 Argumentos e parmetros

Argumentos so os valores usados para chamar a funo e parmetros so as variveis, declaradas na definio da funo, que recebem estes argumentos. Observe o exemplo abaixo:
/* Argumentos e parmetros */ #include <stdio.h> int soma(int a, int b) /* "a" e "b" so os parmetros da funo "soma" */ { int resultado; resultado = a + b; return(resultado); } int main() { printf("A soma entre 5 e 2 %d\n",soma(5,2)); /* No comando printf acima a funo "soma" chamada * com os argumentos 5 e 2 */ return(0); }

Os tipos dos argumentos devem ser compatveis com os tipos dos parmetros. Voc encontrar tambm referncia aos parmetros formais e paramros reais. Os parmetros formais so os parmetros propriamente ditos, enquanto que os parmtros reais so os argumentos.

8.4 Parmetros
Existem duas formas de declarao de parmetros em funes: a forma clssica e a forma moderna. A forma clssica tem a seguinte sintaxe:
TIPO NOME(PARMETRO1, PARMETRO2, ... , PARMETROn) TIPO DO PARMETRO1; TIPO DO PARMETRO2; ... ... TIPO DO PARMETROn; { CORPO DA FUNO }

J a forma moderna tem a seguinte sintaxe:


TIPO NOME(TIPO PARMETRO1, TIPO PARMETRO2, ... , TIPO PARMETROn) { CORPO DA FUNO }

Abaixo segue um exemplo de funo com os dois tipos de declarao de parmetros.


/* Com declarao clssica */ int soma(a, b) int a; int b; { int resultado; resultado = a + b; return(resultado); }

/* Com declarao moderna */ int soma(int a, int b) { int resultado; resultado = a + b; return(resultado); }

Atualmente utiliza-se a forma moderna, porm, em programas mais antigos voc encontrar a forma clssica.

8.5 Chamada por valor e chamada por referncia


A chamada por valor a passagem normal do valor dos argumentos para a funo. Utilizando esta chamada os valores dos argumentos passados no so modificados. Na realidade passada uma cpia dos valores para a funo. Na chamada por referncia so passados os endereos de memria onde esto os argumentos. Neste tipo de chamada os valores podem ser modificados. Abaixo segue um exemplo de uma chamada por valor:
/* Testando a chamada por valor */ #include <stdio.h>

/* Funo com chamada por valor */ int valor(int a, int b) { a = a + 3; /* Modificando o primeiro argumento */ b = b + 2; /* Modificando o segundo argumento */ printf("Valores modificados dentro da funo:\n"); printf("nr1 = %d\n",a); printf("nr2 = %d\n",b); }

int main() { int nr1 = 2, nr2 = 3, total; printf("\n"); printf("Chamada por valor\n"); printf("=================\n"); printf("Valores iniciais de nr1 e nr2\n"); printf("nr1 = %d\n",nr1); printf("nr2 = %d\n",nr2); printf("\n\nChamando a funo\n"); valor(nr1,nr2); /* Neste tipo de chamada so passados os argumentos * normalmente. Na verdade a funo recebe uma cpia * destes argumentos */ printf("\n\nValores aps a chamada da funo\n"); printf("nr1 = %d\n",nr1); printf("nr2 = %d\n",nr2); return(0); }

Agora o mesmo exemplo com a chamada por referncia:


/* Testando a chamada por referncia */ #include <stdio.h>

/* Funo com int valor(int { *a = *a + *b = *b +

chamada por referncia */ *a, int *b) 3; /* Modificando o primeiro argumento */ 2; /* Modificando o segundo argumento */

printf("Valores modificados dentro da funo:\n"); printf("nr1 = %d\n",*a); printf("nr2 = %d\n",*b); }

int main() { int nr1 = 2, nr2 = 3, total; printf("\n"); printf("Chamada por referncia\n"); printf("======================\n"); printf("Valores iniciais de nr1 e nr2\n"); printf("nr1 = %d\n",nr1); printf("nr2 = %d\n",nr2); valor(&nr1,&nr2); /* Neste tipo de chamada passado o endereo do * argumento. Neste tipo de chamada os valores * podem ser modificados */ printf("\n\nValores aps a chamada da funo\n"); printf("nr1 = %d\n",nr1); printf("nr2 = %d\n",nr2); return(0); }

OBSERVAO: As strings e matrizes sempre so chamadas por referncia. Quando C passa uma matriz ou string para uma funo passado o endereo inicial da matriz ou funo.

8.6 Argumentos da linha de comando


Caso queira, voc pode passar argumentos diretamente para a funo main(). Como main () a primeira funo a ser chamada quando voc chama o programa os argumentos para ela so passados junto com o comando que chama o programa, geralmente seu nome. Estes argumentos so conhecidos como argumentos da linha de comando. Observe o exemplo abaixo:
#include <stdio.h> int main(int argc, char *argv[]) { printf("Ol %s.\n",argv[1]); return(0); }

Os argumentos da linha de comando so argc e argv. argc armazena o nmero de argumentos passados para o programa, inclusive o nome do programa. argv uma matriz de strings e armazena o nome do programa e os argumentos passados. argv[0] armazena o nome do programa, argv[1] armazena o primeiro

argumento passado para o programa, argv[2] armazena o segundo argumento passado para o programa, e assim por diante. Os argumentos so seprarados por um espao.

8.7 O comando return


O comando return usado para encerrar a funo e retornar um valor para a funo chamadora. Exemplo:
#include <stdio.h> float total(float preco, float taxa_juros) { float preco_final, juros; juros = preco * (taxa_juros / 100); preco_final = preco + juros; return(preco_final); } int main() { float preco, taxa_juros, preco_final; printf("\n"); printf("Preo na etiqueta :"); scanf("%f",&preco); printf("\n"); printf("Taxa de juros :"); scanf("%f",&taxa_juros); preco_final = total(preco, taxa_juros); printf("\n"); printf("Total a pagar : %4.2f\n\n",preco_final); return(0); }

O valor retornado por return deve ser compatvel com o tipo da funo, o qual definido quando da sua declarao.
float total(float preco, float taxa_juros)

No exemplo, a funo total retorna um valor float. Isto determinado pela colocao do tipo float antes do nome da funo, como mostrado acima. Se uma funo no retornar nenhum valor ela do tipo void. Exemplo:
#include <stdio.h> void nao_retorna() { printf("Esta funo no retorna nada.\n"); } int main() { nao_retorna(); return(0); }

De acordo com o padro ANSI, a funo main devolve um inteiro para o processo chamador, que geralmente o sistema operacional. Isto equivalente a chamar exit com o mesmo valor. Alguns compiladores ainda aceitam que main seja declarada como void caso no retorne nenhum valor.

8.8 Prottipo de funo


A chamada a uma funo deve vir, a princpio, aps sua definio para o compilador conhecer os tipos de parmetros e o tipo de retorno da funo. Porm, voc pode chamar a funo antes da definio desta. Para isso declare apenas um prottipo da funo, o qual tem apenas o valor de retorno e os parmetros da funo. Observe o exemplo abaixo:
#include <stdio.h> int soma(int a, int b); /* prottipo da funo */ int main() { int nr1, nr2; printf("Entre com o primeiro nmero :"); scanf("%d",&nr1); printf("Entre com o segundo nmero :"); scanf("%d",&nr2); printf("\n%d + %d = %d\n\n",nr1,nr2,soma(nr1,nr2)); return(0); } int soma(int a, int b) /* funo propriamente dita */ { int resultado; resultado = a + b; return(resultado); }

8.9 Recurso
Recurso o ato de uma funo chamar ela mesma. Uma funo que chama a ela mesma chamada funo recursiva. O exemplo padro de funo recursiva uma funo que calcula o fatorial de um nmero. O fatorial de um nmero igual ao produto dos nmeros inteiros de 1 at o nmero.
fatorial de 5 = 5 * 4 * 3 * 2 * 1

Se voc observar com cuidado ver que:


fatorial fatorial fatorial fatorial de de de de 5 4 3 2 = = = = 5 4 3 2 * * * * fatorial fatorial fatorial fatorial de de de de 4 3 2 1

Ou seja
fatorial de um nmero = nmero * (fatorial de nmero - 1)

Desta concluso podemos escrever nosso exemplo de funo recursiva:


/* Exemplo de funo recursiva */ #include <stdio.h> int fatorial(nr) { int resposta; if(nr == 1)

return(1); resposta = nr * fatorial(nr-1); return(resposta); }

int main() { int a; printf("\nEntre com um valor inteiro :"); scanf("%d",&a); printf("O fatorial de %d %d\n\n",a,fatorial(a)); return(0); }

A recurso sempre deve ser evitada basicamente por dois fatores. Primeiro que uma funo recursiva difcil de compreender. Segundo que as funes recursivas so mais lentas que suas correspondentes no recursivas. Normalmente uma funo recursiva tambm pode ser escrita com laos de repetio tipo for ou while de modo a remover a recurso.

9. E/S (Entrada/Sada)

9.1 Lendo um caracter do teclado


Para ler um caracter do teclado utilize a funo getchar( ). Ela faz parte do arquivo de cabealho stdio.h. Sua utilizao :
variavel = getchar();

Esta funo retorna o valor inteiro referente ao cdigo ASCII do caractere lido, porm voc pode atribuir este valor a uma varivel do tipo caracter. Caso ocorra um erro, ela retorna EOF. Abaixo segue um exemplo da utilizao de getchar:
/* Exemplo da utilizao de getchar */ #include <stdio.h> int main() { char caracter; printf("\n"); printf("Utilizando getchar()\n"); printf("--------------------\n"); printf("\n"); printf("Entre com um caracter :"); caracter = getchar(); printf("\nVoc digitou o caracter %c\n\n",caracter); return(0); }

9.2 Exibindo um caracter


Para exibir um caracter voc pode usar a funo putchar( ) que est no arquivo de cabealho stdio.h. Sua sintaxe :

putchar(variavel)

Onde variavel um nmero inteiro, porm voc pode passar variavel como um caracter. putchar retorna o caracter exibido ou EOF, caso ocorra algum erro. Exemplo:
/* Exemplo da utilizao de putchar */ #include <stdio.h> int main() { char caracter; printf("\n"); printf("Utilizando putchar()\n"); printf("--------------------\n"); printf("\n"); printf("Entre com um caracter :"); caracter = getchar(); printf("\nExibindo o caracter com putchar => "); putchar(caracter); printf("\n\n"); return(0); }

9.3 Lendo uma string do teclado


Voc pode ler uma string do teclado usando as funes gets( ) e fgets(). Elas fazem parte do arquivo de cabealho stdio.h. O gcc desencoraja o uso de gets . A prpria man page de gets declara o seguinte em sua seo PROBLEMAS :
PROBLEMAS Nunca use gets(). Porque impossvel saber, sem conhecer antecipada mente os dados, quantos caracteres gets() vai ler, e porque gets() vai continuar a guardar caracteres ultrapassado o fim do 'buffer', ela extremamente perigosa de usar. Este comportamento tem sido utilizado para quebrar a segurana de computadores. Use fgets() no seu lugar.

Por isso que s abordarei a sintaxe de fgets, que a seguinte:


fgets(STRING,TAMANHO,STREAM);

onde:

STRING a varivel onde a string ser armazenada TAMANHO o tamanho mximo da string STREAM de onde os caracteres sero lidos, para ler do teclado o valor padro para isto stdin

Exemplo do uso de fgets:


/* usando fgets para ler uma string do teclado */ #include <stdio.h> int main()

{ char frase[50]; printf("Digite uma frase qualquer:"); fgets(frase,50,stdin); printf("\n"); printf("Exibindo\n\n"); printf("%s\n",frase); return(0); }

9.4 Exibindo uma string


Voc pode exibir uma string usando a funo printf ou a funo puts( ). Elas fazem parte do arquivo de cabealho stdio.h. A sintaxe de printf para a exibir uma string ;
printf("%s",STRING);

Exemplo:
#include <stdio.h> int main() { char string[30]; printf("\n"); printf("Exemplo do uso de printf para exibir strings\n"); printf("---------------------------------------------\n"); printf("Digite uma string :"); fgets(string,30,stdin); printf("\n"); printf("A string digitada foi :%s",string); printf("\n\n"); return(0); }

A sintaxe de puts :
puts(string)

Exemplo:
#include <stdio.h> int main() { char string[30]; printf("\n"); printf("Exemplo do uso de puts\n"); printf("----------------------\n"); printf("\n"); printf("Digite uma string :"); fgets(string,30,stdin); printf("\n"); printf("A string digitada foi :",string); puts(string); printf("\n\n");

return(0); }

9.5 Sada formatada (printf)


A sada formatada feita utilizando a funo printf vista anteriormente. printf faz parte do arquivo de cabealho stdio.h

9.6 Entrada formatada (scanf)


A entrada formatada feita utilizando a funo scanf.Ela faz parte do arquivo de cabealho stdio.h. Sua sintaxe :
scanf("especificador de formato",&varivel)

O especificador de formato segue a mesma sintaxe da funo printf. Observe que o valor entrado passado para o endereo da varivel. No caso de leitura de uma string no h necessidade do operador &, j que o nome de uma string sem o ndice entendido pela linguagem C como um ponteiro para o incio da string. Abaixo segue um exemplo do uso de scanf:
# include<stdio.h> int main() { int qde; float preco,total; char produto[20]; printf("\n"); printf("Produto :"); scanf("%s",produto); printf("\n"); printf("Preo :"); scanf("%f",&preco); printf("\n"); printf("Quantidade :"); scanf("%d",&qde); printf("\n"); printf("Produto\tPreo\tQde\tTotal\n"); printf("%s\t%.2f\t%d\t%.2f\n\n",produto,preco,qde,qde*preco); return(0); }

10. Funes matemticas

10.1 Obtendo o valor absoluto de um nmero inteiro


Para obter o valor absoluto de um nmero inteiro use a funo abs( ). Ela faz parte do arquivo de cabaalho stdlib.h e sua sintaxe :
abs(nmero)

Exemplo do uso da funo abs:


#include <stdio.h> int main()

{ int nr1 = 5,nr2 = -7; printf("\n"); printf("nr1=%d\tabs(nr1)=%d\n",nr1,abs(nr1)); printf("nr2=%d\tabs(nr2)=%d\n\n",nr2,abs(nr2)); return(0); }

10.2 Funes trigonomtricas


O arquivo de cabealho tgmath.h (ou math.h, dependendo do seu compilador) fornece as seguintes funes trigonomtricas:
sin(angulo) cos(angulo) tan(angulo)

Estas calculam o seno, co-seno e tangenge de angulo. Todas recebem e retornam um valor double. O argumento angulo passado para as funes especificado em radianos.

Alm destas devem ser encontradas as funes:


asin(angulo) acos(angulo) atan(angulo)

Para o clculo de arco seno, arco co-seno e arco tangente e:


sinh(angulo) cosh(angulo) tanh(angulo)

Para o clculo do seno, co-seno e tangente hiperblicos. Para maiores detalhes d uma estudada no arquivo de cabealho referente na biblioteca de seu compilador.

10.3 Gerando nmeros aleatrios


Para gerar nmeros aleatrios alguns compiladores possuem em seu arquivo de cabealho stdlib.h as funes random( ) e rand( ). A funo random gera um nmero aleatrio entre zero e um nmero inteiro passado como argumento. Sua sintaxe :
random(nmero)

J a funo rand gera um nmero aleatrio entre zero e RAND_MAX que definido no prprio arquivo stdlib.h. A sintaxe de rand :
rand( )

Abaixo segue um exemplo do uso destas funes:


/* gerando nmeros aleatrios */

#include <stdio.h> #include <stdlib.h> int main() { int contador; printf("Gerando 5 nmeros aleatrios com random\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",random(10));

printf("Gerando 5 nmeros aleatrios com rand\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",rand()); return(0); }

Porm, ao executar o programa acima vrias vezes, voc ver que ele sempre gera os mesmos nmeros aleatrios. Para resolver isso basta utilizar as funes randomize( ) e srand( ) que iniciam o gerador de nmeros aleatrios. inicia o gerador de nmeros aleatrios usando o relgio do computador para produzir uma semente aleatria e srand( ) lhe permite especificar o valor inicial do gerador de nmeros aleatrios. Sua sintaxe :
randomize srand(nmero)

Veja como fica nosso exemplo inicial usando randomize para iniciar o gerador de nmeros aleatrios:
/* gerando nmeros aleatrios */ #include <stdio.h> #include <stdlib.h> int main() { int contador; randomize(); printf("Gerando 5 nmeros aleatrios com random\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",random(10));

printf("Gerando 5 nmeros aleatrios com rand\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",rand()); return(0); }

At aqui tudo bem. Porm ao utilizar este cdigo no gcc obtive uma mensagem de erro dizendo que a funo random tinha muitos argumentos. Dei uma olhada no arquivo de cabealho stdlib.h e vi que neste compilador as coisas funcionam de maneira um pouco diferente.
random e rand RAND_MAX.

aparentemente tem a mesma funo, ou seja, geram nmeros aleatrios entre zero e

definido como igual a 2147483647. Assim eu dividi o resultado de random por 100000000 e consegui alguns aleatrios com dois dgitos:
RAND_MAX /* gerando nmeros aleatrios no gcc */ #include <stdio.h> #include <stdlib.h> /* random() gera um long int entre 0 e RAND_MAX = 2147483647 * * RAND_MAX definido em stdlib.h */ int main() { int contador; printf("Gerando 5 nmeros aleatrios com random\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",random()/100000000);

printf("Gerando 5 nmeros aleatrios com rand\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",rand()/100000000); return(0); }

Para iniciar o gerador de nmeros aleatrios a funo randomize no existe, porm, a funo srandom existe. Ento eu a utilizei juntamente com a funo time e consegui gerar nmeros aleatrios diferentes a cada execuo do programa. O cdigo anterior ficou assim:
/* gerando nmeros aleatrios no gcc */ #include <stdio.h> #include <stdlib.h> /* random() gera um long int entre 0 e RAND_MAX = 2147483647 * * RAND_MAX definido em stdlib.h */ int main() { int contador; srandom(time(NULL)); /* iniciando o gerador de nmeros aleatrios */ printf("Gerando 5 nmeros aleatrios com random\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",random()/100000000);

printf("Gerando 5 nmeros aleatrios com rand\n"); for(contador=1;contador <= 5; contador++) printf("%d\n",rand()/100000000); return(0); }

11. Arquivos

11.1 Introduo

O sistema de E/S de C utiliza o conceito de streams e arquivos. Uma stream um dispositivo lgico que representa um arquivo ou dispositivo. A stream independente do arquivo ou dispositivo. Devido a isso, a funo que manipula uma stream pode escrever tanto em um arquivo no disco quanto em algum outro dispositivo, como o monitor. Existem dois tipos de streams: de texto e binria. Em uma stream de texto podem ocorrer certas tradues de acordo com o sistema hospedeiro. Por exemplo, um caracter de nova linha pode ser convertido para os caracteres retorno de carro e alimentao de linha. Devido a isso pode no haver uma correspondncia entre os caracteres da stream e do dispositivo externo; a quantidade de caracteres pode no ser a mesma. A stream binria uma sequncia de bytes com uma correspondncia de um para um com os bytes encontrados no dispositivo externo, isto , no ocorre nenhuma traduo de caracteres. O nmero de bytes o mesmo do dispositivo. Um arquivo interpretado pela linguagem C como qualquer dispositivo, desde um arquivo em disco at um terminal ou uma impressora. Para utilizar um arquivo voc deve associ-lo a uma stream e, ento, manipular a stream. Voc associa um arquivo a uma stream atravs de uma operao de abertura. Nem todos os arquivos tem os mesmos recursos. Por exemplo, um arquivo em disco pode suportar acesso aleatrio enquanto um teclado no. Do que foi at aqui exposto conclumos que todas as streams so iguais, mas no todos os arquivos. Se o arquivo suporta acesso aleatrio, abr-lo inicializa o indicador de posio apontando para o comeo do arquivo. Quando cada caracter lido ou escrito no arquivo, o indicador de posio incrementado. Um arquivo desassociado de uma stream atravs de uma operao de fechamento. Se um arquivo aberto para sada por fechado, o contedo de sua stream ser escrito no dispositivo externo. Esse processo geralmente chamado de descarga (flushing) da stream e garante que nenhuma informao seja acidentalmente deixada no buffer de disco. A stream associa o arquivo a uma estrutura do tipo FILE. Esta estrutura definida no arquivo de cabealho
stdio.h

11.2 Funes utilizadas para manipulao de arquivos


As principais funes para manipulao de arquivos so:
FUNO
fopen( )

FINALIDADE Abrir um arquivo

fclose( ) Fechar um arquivo putc( )

Escrever um caracter em um arquivo Idem putc( ) Ler um caracter de um arquivo

fputc( )

getc( )

fgetc( )

Idem getc( ) Posicionar o ponteiro de arquivo num byte especfico para o arquivo o que printf para o console

fseek( ) fprintf( )

fscanf( ) para o arquivo o que scanf para o console feof( )

Devolve verdadeiro se o fim do arquivo foi atingido

ferror( ) Devolve verdadeiro se ocorreu um erro rewind( ) Posicionar o ponteiro de arquivo no incio deste remove( ) Apagar um arquivo fflush( ) Descarregar um arquivo

Todas estas funes esto no arquivo de cabealho stdio.h. Este arquivo de cabealho define trs tipos: size_t, fpos_t e FILE. Os dois primeiros so o mesmo que unsigned e o terceiro discutido mais abaixo. Este arquivo de cabealho tambm define vrias macros. As importantes para a manipulao de arquivos so: NULL, EOF, FOPEN_MAX, SEEK_SET, SEEK_CUR e SEEK_END. NULL define um ponteiro nulo. EOF geralmente definida como -1 e devolve este valor quando uma funo de entrada tenta ler alm do final do arquivo. FOPEN_MAX define um valor inteiro que determina o nmero de arquivos que podem ser abertos ao mesmo tempo. SEEK_SET, SEEK_CUR e SEEK_END so usadas com a funo fssek( ) para o acesso aleatrio a um arquivo.

11.3 O ponteiro de arquivo


Basicamente um ponteiro de arquivo identifica um arquivo especfico e usado pela stream para direcionar as operaes das funes de E/S. Um ponteiro de arquivo uma varivel ponteiro do tipo FILE. Esta varivel um tipo pr-definido pela linguagem C. Normalmente ela definida no arquivo de cabealho stdio.h, mas isso depende do seu compilador. Para ler ou escrever em arquivos seu programa precisa usar os poteiros de arquivo. Para declarar uma varivel como ponteiro de arquivo use a seguinte sintaxe:
FILE *arquivo;

11.4 Abrindo um arquivo

Apesar do sistema de E/S de C considerar arquivo como qualquer dispositivo, para os conceitos apresentados daqui pra frente, consideraremos arquivo como um arquivo em disco. Para abrir uma stream e associ-la a um arquivo voc usa a funo fopen( ) ,cuja sintaxe :
fopen(ARQUIVO,MODO)

Onde ARQUIVO um ponteiro para uma string que representa o nome do arquivo. Na prtica o nome do arquivo propriamente dito e pode ser um PATH, ou seja, algo como "C:\docs\arquivo.txt", no windows; ou algo como "/home/samu/arquivo.txt" no linux. MODO uma string que representa como o arquivo ser aberto de acordo com a tabela abaixo:
MODO
r

COMO O ARQUIVO SER ABERTO Abre um arquivo texto para leitura. Abre um arquivo texto para escrita. Se um arquivo com o mesmo nome existir, ser sobrescrito. Abre um arquivo texto para anexao. Se o arquivo no existir, ser criado. Abre um arquivo binrio para leitura. Abre um arquivo binrio para escrita. Se um arquivo com o mesmo nome existir, ser sobrescrito. Abre um arquivo binrio para anexao. Se o arquivo no existir, ser criado.

rb

wb

ab r+ w+ a+ r+b w+b a+b rb+ wb+ ab+

Abre um arquivo texto para leitura/escrita. Se o arquivo no existir, ser criado.

Abre um arquivo binrio para leitura/escrita. Se o arquivo no existir, ser criado.

importante lembrar que em muitas implementaes, no modo texto, a sequncia de caracteres retorno de carro/alimentao de linha so traduzidas para nova linha na entrada. Na sada ocorre o inverso: caracteres de nova linha so convertidos em retorno de carro/alimentao de linha. Em arquivos binrios no ocorre nenhuma traduo. Caso tudo corra bem, a funo fopen devolve um ponteiro de arquivo, caso ocorra algum problema ela devolve NULL. Para abrir um arquivo texto chamado "teste" para escrita voc poderia escrever assim:
FILE *arquivo; arquivo = fopen("teste","w");

Porm, recomendvel sempre testar se o arquivo foi aberto sem problemas. Assim, sempre que for abrir um arquivo, voc deve usar um cdigo parecido com este:
FILE *arquivo; if((arquivo = fopen("teste","w")) == NULL) { printf("Erro ao abrir arquivo!!!\n"); exit(1); }

Este tipo de teste detectar algum problema tipo disco cheio ou protegido contra gravao antes que seu programa tente gravar nele. O nmero mximo de arquivos que pode ser aberto ao mesmo tempo definido pela macro FOPEN_MAX, normalmente definida em stdio.h. Confira se o caso do seu compilador.

11.5 Fechando um arquivo


Para fechar uma stream voc deve usar a funo fclose( ). Ela escreve qualquer dado que ainda permanece no buffer de disco no arquivo e o fecha em nvel de sistema operacional. Uma falha ao fechar uma stream pode provocar problemas tipo perda de dados, arquivos destrudos e erros intermitentes em seu programa. fclose tambm libera o bloco de controle de arquivo associado stream deixando-o disponvel para reutilizao. Como, normalmente, h um limite do sistema operacional para o nmero de arquivos abertos ao mesmo tempo, voc deve fechar um arquivo antes de abrir outro. A sintaxe de fclose :
fclose(ARQUIVO);

Onde ARQUIVO o ponteiro de arquivo devolvido por fopen quando esta abriu o arquivo. Caso o fechamento do arquivo ocorra sem problemas, fclose retorna zero. Qualquer outro valor indica erro. Erros possveis so floppy drive sem disquete ou disco cheio.

11.6 Escrevendo e lendo caracteres


Para escrever um caracter num arquivo aberto voc pode usar duas funes: putc( ) ou fputc( ). Elas so identicas. Existem as duas para preservar a compatibilidade com verses mais antigas do C. lgico que para escrever num arquivo este deve ter sido aberto num modo que permita a escrita. Veremos putc( ). Sua sintaxe :
putc(CARACTER,ARQUIVO);

Onde CARACTER o caracter a ser escrito no arquivo e ARQUIVO um ponteiro de arquivo. Se ocorrer tudo bem, a funo retorna o caracter escrito, caso contrrio ela retorna EOF. Para ler um caracter temos tambm duas funes: getc( ) e fgetc( ). Existem duas tambm pelo motivo da compatibilidade com verses mais antigas da linguagem C. O arquivo deve ter sido aberto num modo que permita a leitura. Veremos getc( ). Sua sintaxe :

getc(ARQUIVO);

Onde ARQUIVO um ponteiro de arquivo. Quando o final do arquivo alcanado a funo devolve EOF. Para ler o contedo de um arquivo voc poderia usar um trecho de cdigo parecido com:
do { caracter = getc(arquivo); } while(caracter != EOF);

Sendo caracter uma varivel char e arquivo uma varivel ponteiro para uma estrutura FILE. importante observar que getc tambm devolve EOF caso ocorra algum erro.

11.7 Programa que l e exibe o contedo de um arquivo texto


/* lendo e exibindo o contedo de um arquivo texto */ #include <stdio.h> int main(int argc, char *argv[]) { char caracter; FILE *arquivo; if(argc < 2) { printf("\nErro: Digite o nome do arquivo !!!\n\n"); exit(1); } printf("\n%s\n\n",argv[1]); if((arquivo = fopen(argv[1],"r")) == NULL) { printf("Erro ao abrir arquivo!!!\n\n"); exit(1); }; do { caracter = getc(arquivo); putchar(caracter); } while(caracter != EOF); printf("\n\n"); fclose(arquivo); return(0); }

Observe que este cdigo exibe tambm o caracter EOF. Um bom exerccio reescrever este cdigo de modo que este caracter no seja exibido.

11.8 Programa que escreve caracteres num arquivo

/* escrevendo caracteres num arquivo */ #include <stdio.h> int main(int argc, char *argv[]) { FILE *arquivo; char caracter; if(argc < 2) { printf("\nErro: Digite o nome do arquivo !!!\n\n"); exit(1); } if((arquivo = fopen(argv[1],"w")) == NULL) { printf("Erro ao abrir arquivo!!!\n\n"); exit(1); } do { caracter = getchar(); putc(caracter,arquivo); } while(caracter != '$'); fclose(arquivo); printf("\nGravado com sucesso em %s\n\n",argv[1]); return(0); }

11.9 Verificando o final de um arquivo binrio


Quando manipulando dados binrios um valor inteiro igual a EOF pode ser lido por engano. Isso poderia fazer com que fosse indicado o fim de arquivo antes deste ter chegado. Para resolver este problema C inclui a funo feof( ) que determina quando o final de um arquivo foi atingido. Ela tem a seguinte sintaxe:
feof(ARQUIVO);

onde ARQUIVO um ponteiro de arquivo. Esta funo faz parte de stdio.h e devolve verdadeiro caso o final de arquivo seja atingido; caso contrrio ela devolve 0. Para ler um arquivo binrio voc poderia usar o seguinte trecho de cdigo:
while(!feof(arquivo)) caracter = getc(arquivo);

11.10 Programa que copia arquivo


/* programa que copia arquivo */ #include <stdio.h> int main(int argc, char *argv[]) { FILE *original,*copia; char caracter; if(argc < 3)

{ printf("\nSintaxe correta:\n\n"); printf("copiar ARQUIVO_ORIGEM ARQUIVO_DESTINO\n\n"); exit(1); }

while(argv[1]) { if(*argv[1] == *argv[2]) break; printf("\nO nome do arquivo original no pode ser igual ao da\ cpia.\n\n"); exit(1); };

if((original = fopen(argv[1],"rb")) == NULL) { printf("\nErro ao abrir o arquivo original.\n\n"); exit(1); } if((copia = fopen(argv[2],"wb")) == NULL) { printf("\nErro ao abrir o arquivo cpia.\n\n"); exit(1); } while(!feof(original)) { caracter = getc(original); if(!feof(original)) putc(caracter,copia); } fclose(original); fclose(copia); printf("\n%s copiado com sucesso com o nome de %s.\n\n",argv[1],argv[2]); return(0); }

11.11 Escrevendo e lendo strings


Para escrever e ler strings em um arquivo use as funes fputs( ) e fgets( ), cujos prottipos encontramse em stdio.h.
fputs( )

escreve uma string na stream especificada, sua sintaxe :

fputs(STRING,ARQUIVO);

onde ARQUIVO um ponteiro de arquivo. Caso ocorra algum erro esta funo retorna EOF.
fgets( )

l uma string da stream especificada. Sua sintaxe :

fgets(STRING,TAMANHO,ARQUIVO);

Ela l STRING at que um caractere de nova linha seja lido ou que TAMANHO - 1 caracteres tenham sido lidos. Se uma nova linha lida ela ser parte da string. A string resultante terminar em nulo. Caso ocorra tudo bem esta funo retornar um ponteiro para STRING, caso contrrio, retornar um ponteiro nulo.

11.12 Programa que escreve strings num arquivo


/* Programa que escreve strings num arquivo. * * Para encerrar o programa o usurio dever inserir uma * linha em branco. * * Como gets() no armazena o caractere de nova linha, * adicionado um antes da string ser gravada no arquivo. * Isto feito para que a string possa ser lida, posteriormente, * com fgets() j que esta funo l a string at que seja * encontrado um caracter de nova linha. */ #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { char string[80]; FILE *arquivo; if(argc < 2) { printf("\nErro: Digite o nome do arquivo !!!\n\n"); exit(1); }

if((arquivo = fopen(argv[1],"w")) == NULL) { printf("Erro ao abrir arquivo!!!\n\n"); exit(1); } do { gets(string); strcat(string,"\n"); fputs(string,arquivo); } while(*string != '\n'); fclose(arquivo); return(0); }

11.13 Apontando para o incio do arquivo


Para apontar para o incio do arquivo use a funo rewind( ), cujo prottipo est no arquivo de cabealho stdio.h. Sua sintaxe :
rewind(ARQUIVO);

sendo ARQUIVO um ponteiro de arquivo.

11.14 Verificando se a operao com o arquivo produziu um erro


Para determinar se uma operao com o arquivo produziu um erro use a funo ferror( ). Seu prottipo est em stdio.h e sua sintaxe :
ferror(ARQUIVO);

sendo ARQUIVO um ponteiro de arquivo. Esta funo retorna verdadeiro se ocorreu um erro durante a ltima operao com o arquivo, caso contrrio retorna falso. Como cada operao modifica a condio de erro, ela deve ser chamada logo aps cada operao realizada com o arquivo.

11.15 Apagando um arquivo


Para apagar uma arquivo use a funo remove( ). Ela faz parte de stdio.h e sua sintaxe :
remove(ARQUIVO);

sendo ARQUIVO um ponteiro de arquivo. Exemplo:


/* Apagando um arquivo */ #include <stdio.h> #include <ctype.h> int main(int argc,char *argv[]) { FILE * arquivo; char opcao[5]; if(argc != 2) { printf("Erro !!! \n"); printf("Sintaxe correta: apagar ARQUIVO\n"); exit(1); } printf("Deseja realmente apagar o arquivo %s (S/N)?",argv[1]); gets(opcao); if(toupper(*opcao) == 'S') if(remove(argv[1])) { printf("Erro ao tentar apagar arquivo.\n"); exit(1); } else printf("Arquivo apagado com sucesso.\n"); return(0); }

11.16 Renomeando ou Movendo um arquivo


Para renomear um arquivo use a funo rename( ). Ela est em stdio.h e sua sintaxe :
rename(NOME_ANTIGO, NOVO_NOME);

onde NOME_ANTIGO e NOVO_NOME so ponteiros string. Se a funo for bem sucedida ela retornar zero, caso contrrio, retornar um valor diferente de zero. Esta mesma funo serve para mover um arquivo. Basta incluir a nova localizao como parte do NOVO_NOME do arquivo. Observe o exemplo abaixo:
/* renomeando ou movendo um arquivo */ #include <stdio.h>

int main(int argc,char *argv[]) { if(argc != 3) { printf("Erro !!! \n"); printf("Sintaxe correta: renomear NOME_ANTIGO NOVO_NOME\n"); exit(1); } if(rename(argv[1],argv[2])) printf("Erro ao renomear arquivo!\n"); return(0); }

Este programa renomeia um arquivo. Porm, se voc especificar um outro local para o novo nome do arquivo, este, alm de ser renomeado, ser movido. Crie um arquivo chamado teste em seu diretrio de usurio e, aps compilar o exemplo acima com o nome de renomear, digite o seguinte comando:
$ renomear teste teste123

liste o contedo do diretrio e voc ver que o arquivo foi renomeado. Agora crie um diretrio chamado lixo e digite o comando:
$ renomear teste123 lixo/teste456

d uma checada e voc ver que o arquivo teste123 no existe mais no diretrio atual, mas em lixo foi criado o arquivo teste456, mostrando que teste123 foi movido e renomeado.

11.17 Esvaziando uma stream


Para esvaziar o contedo de uma stream aberta para sada use a funo fflush( ). Sua sintaxe :
fflush(ARQUIVO);

sendo ARQUIVO um ponteiro de arquivo. Ela escreve o conteudo do buffer para o arquivo passado como argumento. Se for passado um valor nulo, todos os arquivos abertos para sada sero descarregados. Se tudo ocorrer bem fflush retornar zero, indicando sucesso. Caso contrrio, devolver EOF.

11.18 Escrevendo e lendo tipos de dados definidos pelo usurio


Veremos mais a frente que C permite que o usurio crie seus prprios tipos de daos. Este tipos de dados so estruturas compostas de tipos de dados simples e com estas estruturas podemos construir registros. Para escrever e ler estas estruturas podemos usar as funes fread( ) e fwrite( ). Elas so definidas em stdio.h. A sintaxe de fread( ) :
fread(VARIVEL,TAMANHO,QUANTIDADE,ARQUIVO);

onde:

VARIVEL o endereo da varivel que receber os dados lidos do arquivo TAMANHO o nmero de bytes a ser lido. Para calcular isso voc deve usar o operador sizeof QUANTIDADE indica quantos itens sero lidos (cada item do tamanho de TAMANHO)

ARQUIVO um ponteiro para o arquivo aberto anteriormente

A sintaxe para fwrite( ) idntica, com a exceo que VARIVEL o endereo da varivel com os dados a serem escritos no arquivo. O ponteiro de arquivo "ARQUIVO" deve ser aberto em modo binrio, para podermos ler e escrever qualquer tipo de informao. Tambm deve ser aberto de acordo com a operao a ser feita (leitura ou escrita). devolve o nmero de itens lidos. Esse valor poder ser menor que QUANTIDADE se o final do arquivo for atingido ou ocorrer um erro.
fread fwrite

devolve o nmero de itens escritos. Esse valor ser igual a QUANTIDADE a menos que ocorra um erro.

Abaixo segue um exemplo do uso de fwrite. Vamos escrever alguns dados num arquivo.
/* Usando fwrite para escrever dados num arquivo */ #include <stdio.h> int main() { FILE *arquivo; char nome[5]="samu"; int idade=34; float altura=1.82; if((arquivo = fopen("samu.dat","wb")) == NULL) { printf("Erro ao abrir arquivo!!!\n\n"); exit(1); } fwrite(&nome,sizeof(nome),1,arquivo); fwrite(&idade,sizeof(idade),1,arquivo); fwrite(&altura,sizeof(altura),1,arquivo); fclose(arquivo); return(0); }

Agora veremos um exemplo com o uso de fread que ler o arquivo "samu.dat" criado no exemplo acima:
/* Usando fread para ler dados de um arquivo */ #include <stdio.h> int main() { FILE *arquivo; char nome[5]; int idade; float altura; if((arquivo = fopen("samu.dat","rb")) == NULL) { printf("Erro ao abrir arquivo!!!\n\n"); exit(1); } fread(&nome,sizeof(nome),1,arquivo); fread(&idade,sizeof(idade),1,arquivo); fread(&altura,sizeof(altura),1,arquivo);

printf("nome : %s\n",nome); printf("idade : %d\n",idade); printf("altura: %.2f\n",altura); fclose(arquivo); return(0); }

Embora no tenha sido feito nestes dois exemplos, interessante, em programas maiores, a anlise do retorno de fread e fwrite para ver se no ocorreram erros. Isto pode ser feito com uma instruo deste tipo:
if(fread(&nome,sizeof(nome),1,arquivo) != 1) printf("Erro de leitura.\n");

11.19 Apontando para uma posio especfica dentro do arquivo


Voc pode apontar para um byte especfico dentro do arquivo movimentando o indicador de posio. Isto pode ser feito com o uso da funo fseek( ),cuja sintaxe :
fseek(ARQUIVO, NMERO_DE_BYTES, ORIGEM);

onde ARQUIVO um ponteiro de arquivo aberto anteriormente, NMERO_DE_BYTES a quantidade de bytes que o indicador de posio ser movimentado e ORIGEM a partir de onde o movimento do indicador de posio iniciar.
ORIGEM

deve ser uma das seguintes macros:


SEEK_SET para a origem no incio do arquivo SEEK_CUR para a origem na posio atual do indicador de posio SEEK_END para a origem no final do arquivo

estas macros esto definidas em stdio.h. deve ser usado em conjunto com sizeof para que possamos acessar os tipos de dados prdefinidos. Por exemplo, digamos que criamos um tipo de dado chamado "ficha", onde armazenamos os dados de um livro como ttulo, autor, editora, etc... e escrevemos vrios dados em um arquivo. Se quisermos apontar o indicador de posio para o quinto registro deste arquivo deveremos usar algo como:
NMERO_DE_BYTES fseek(arquivo,4*sizeof(struct ficha),SEEK_SET);

11.20 Entrada e sada formatadas direcionadas para arquivos


Existem as funes fprintf( ) e fscanf( ) que so semelhantes a printf e a scanf mas que direcionam os dados para arquivos. Abaixo voc pode ver a sintaxe destas funes:
fprintf(ARQUIVO,"ESPECIFICADOR",VARIVEL); fscanf(ARQUIVO,"ESPECIFICADOR",VARIVEL);

onde ARQUIVO um ponteiro de arquivo aberto para onde so direcionados os resultados das funes. Abaixo segue um exemplo do uso destas funes:
/* exemplo do uso de fscanf e fprintf * este programa l uma string do teclado e a escreve num arquivo texto

* compilado com o nome de adtexto */ #include <stdio.h> int main() { FILE *arquivo; char string[80]; if((arquivo = fopen("adtexto.txt","w")) == NULL) { printf("Erro ao abrir o arquivo!\n"); exit(1); } printf("Exemplo do uso de fscanf e fprintf\n"); printf("Digite uma string\n\n"); fscanf(stdin,"%s",string); /* l string do teclado */ fprintf(arquivo,"%s",string); /* escreve string no arquivo */ fclose(arquivo); return(0); }

Embora sejam uma opo atraente para ler e escrever dados em arquivos, estas funes devem ser evitadas pois trabalham com dados ASCII e no binrios o que ocasiona uma perda de desempenho no programa. prefervel o uso de fread e fwrite.

11.21 Streams padro


Quando um programa em linguagem C iniciado so abertas trs streams: stdin, stdout e stderr. stdin define a entrada padro do sistema, normalmente o teclado. stdout define a sada padro do sistema, normalmente o monitor. stderr define a sada padro dos erros, normalmente tambm o monitor. Estas streams so ponteiros de arquivos e podem ser redirecionadas. Assim, nas funes que voc utiliza ponteiros de arquivos para entrada e sada de dados voc pode muito bem usar estas streams de modo ao seu programa receber dados do teclado e escrever no monitor. Isto foi mostrado no exemplo da seo anterior na linha;
fscanf(stdin,"%s",string); /* l string do teclado */

onde o programa leu a varivel string do teclado atravs da streams padro stdin. Porm esteja consciente que estas streams no so variveis e no podem receber um valor. Ou seja, voc no pode abr-las com fopen. Quando o programa encerrado estas streams so fechadas automaticamente, do mesmo jeito que foram criadas, voc no deve nunca tentar abr-las ou fech-las.

12. Matrizes 12.1 Introduo as matrizes


Uma matriz uma estrutura de dados que pode armazenar vrios valores do mesmo tipo.

A sintaxe para declarar uma matriz :


TIPO NOME[QUANTIDADE];

onde TIPO o tipo dos dados que sero armazenados na matriz. Todos os dados colocados na matriz devem ser deste tipo. NOME o nome a ser dado a matriz. Este nome identificar a matriz no cdigo do programa. E QUANTIDADE a quantidade mxima de itens a ser armazenados. Exemplos:
int nr_de_livros[50]; /* esta matriz pode armazenar at 50 valores do tipo int */ float nota[30]; /* esta matriz pode armazenar at 30 valores do tipo float */

Os valores armazenados na matriz so chamados de "elementos da matriz". O primeiro elemento da matriz indexado como item zero e o ltimo indexado como QUANTIDADE menos 1. Assim, para nossa matriz nota, mostrada no exemplo acima, o primeiro elemento nota[0] e o ltimo elemento nota[29]. Voc pode inicializar os elementos de uma matriz na sua declarao usando a sintaxe:
int notas[5] = {60,70,35,50,68};

No exemplo acima o elemento zero da matriz notas receber o valor 60, o elemento 1 receber o valor 70, e assim por diante. Para melhorar o entendimento observe o cdigo abaixo:
#include <stdio.h> int main() { int notas[5] = {60,70,35,50,68}; printf("Analisando os elementos da matriz notas\n"); printf("O primeiro elemento tem o valor %d\n",notas[0]); printf("O segundo elemento tem o valor %d\n",notas[1]); printf("O terceiro elemento tem o valor %d\n",notas[2]); printf("O quarto elemento tem o valor %d\n",notas[3]); printf("O quinto e ltimo elemento tem o valor %d\n",notas[4]); return(0); }

Este cdigo pode ser otimizado usando um lao for e uma varivel para manipular os elementos da matriz. Observe abaixo;
#include <stdio.h> int main() { int notas[5] = {60,70,35,50,68}; int contador; printf("Analisando os elementos da matriz notas\n"); for(contador = 0;contador < 5;contador++) printf("O %do elemento tem o valor %d\n",contador+1,notas[contador]); return(0); }

Uma das matrizes mais comuns utilizadas em C a matriz de caracteres. As strings manipuladas em C so matrizes de caracteres. Observe o exemplo abaixo para um melhor entendimento:
/* visualizando strings como matrizes de caracteres */ #include <stdio.h>

int main() { char palavra[7] = "matriz"; int contador; printf("Em C strings so matrizes de caracteres e podem ser manipuladas como tal.\n"); printf("\nA string %s\n",palavra); printf("\nExibindo cada elemento da matriz palavra\n"); for(contador = 0;contador < 7;contador++) printf("%c\n",palavra[contador]); return(0);

12.2 Passando uma matriz para uma funo


Uma funo que manipula uma matriz deve receber a matriz e a quantidade de elementos. Logicamente ao chamar a funo voc deve passar a matriz propriamente dita e seu nmero de elementos. No h necessidade de passar o tamanho da matriz. Exemplo:
#include <stdio.h> void exibe(int matriz[],int elementos) { int contador; for(contador = 0;contador < elementos;contador++) printf("O %do elemento tem o valor %d\n",contador+1,matriz[contador]); }

int main() { int notas[5] = {60,70,35,50,68}; int contador; printf("Analisando os elementos da matriz notas\n"); exibe(notas,5); return(0); }

Observe os colchetes aps a varivel matriz na declarao da funo exibe. Isto indica que a varivel uma matriz.

12.3 Matrizes bidimensionais


Imagine uma matriz bidimensional como uma tabela de linhas e colunas. Por exemplo, a matriz
pesos[3][5]

pode ser imaginada como:

Observe que o primeiro ndice ([3]) indica as linhas da matriz e o segundo ([5]) indica as colunas. Como sabemos que [3] varia de zero a 2 e [5] varia de zero a 4, fica fcil determinar os ndices de cada posio da matriz:
0,0 1,0 2,0 0,1 1,1 2,1 0,2 1,2 2,2 0,3 1,3 2,3 0,4 1,4 2,4

Visto a posio de cada ndice vamos preencher nossa matriz pesos com valores
10 86 70 30 44 61 45 63 52 70 82 63 36 80 74

De tudo que foi exposto acima podemos entender que:


pesos[1][3] = 82 pesos[0][4] = 36 pesos[0][0] = 10 pesos[2][4] = 74

Para preencher nossa matriz com os valores mostrados na tabela acima podemos usar uma declarao como:
int pesos[3][5] = {{10,30,45,70,36}, {86,44,63,82,80}, {70,61,52,63,74}};

Podemos manipular os elementos de nossa matriz bidimensional usando duas variveis e um lao for da mesma maneira que fizemos com as matrizes comuns. Observe o cdigo abaixo:
/* manipulando uma matriz bidimensional */ #include <stdio.h> int main() { int pesos[3][5] = {{10,30,45,70,36}, {86,44,63,82,80}, {70,61,52,63,74}}; int linha,coluna; for(linha = 0;linha < 3;linha++) for(coluna = 0;coluna < 5; coluna++) printf("elemento[%d][%d] = %d\n",linha,coluna,pesos[linha][coluna]); return(0); }

12.4 Passando uma matriz bidimensional para uma funo


Uma funo que manipula uma matriz bidimensional deve receber a matriz e o nmero de linhas desta matriz. O nmero de colunas da matriz tambm deve estar especificado nesta declarao. Ao chamar a funo, deve-se passar a matriz e o nmero de linhas. Exemplo:
/* manipulando uma matriz bidimensional */ #include <stdio.h> void exibe(int matriz[][5], int linhas) { int linha,coluna; for(linha = 0;linha < 3;linha++) for(coluna = 0;coluna < 5; coluna++) printf("elemento[%d][%d] = %d\n",linha,coluna,matriz[linha][coluna]); }

int main() { int pesos[3][5] = {{10,30,45,70,36}, {86,44,63,82,80}, {70,61,52,63,74}}; exibe(pesos,3); return(0); }

12.5 Pesquisa sequencial


Para procurar um valor especfico numa matriz voc pode usar a pesquisa sequencial. A pesquisa sequencial inicia no primeiro elemento da matriz e vai at o ltimo procurando o valor desejado. Observe abaixo o cdigo de uma pesquisa sequencial numa matriz:
/* exemplo de uma pesquisa sequencial numa matriz */ #include <stdio.h> int main() { int pesos[5]={65,77,84,80,69}; int ok=0,contador,valor; printf("\nmatriz pesos\n\n"); for(contador = 0;contador < 5;contador++) printf("pesos[%d] = %d\n",contador,pesos[contador]); printf("\nEntre com o valor a ser pesquisado :"); scanf("%d",&valor); /* realizando a pesquisa sequencial */ contador=0; while((contador < 5) && (!ok)) if(pesos[contador] == valor) ok = 1; else contador++; if(contador < 5) printf("O valor %d est no elemento pesos[%d]\n",valor,contador); else printf("A matriz pesos no possui o valor %d\n",valor);

return(0); }

Este tipo de pesquisa pode ser demorado quando a matriz possui muitos elementos. Nestes casos use a pesquisa binria que ser vista mais a frente.

12.6 Ordenando os elementos de uma matriz pelo mtodo da bolha


Este mtodo, apesar de simples, consome mais tempo do processador, ento s deve ser usado para matrizes com poucos elementos (em torno de 30). Neste mtodo os elementos da matriz vo sendo percorridos e os pares adjacentes so comparados e ordenados. Isto feito at que toda a matriz esteja ordenada. Para explicar melhor vamos a um exemplo prtico. Imagine a seguinte matriz:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 67 55 86 79 68

Ordenando esta matriz em ordem crescente pelo mtodo da bolha, nosso programa iniciaria compararando o elemento nota[0], que 67, com o elemento nota[1], que 55. Como nota[0] maior que nota[1] os elementos seriam trocados. e nossa matriz ficaria assim:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 86 79 68

Agora nosso programa compararia nota[1] com nota[2] e como os valores esto ordenados no haveria troca. Continuando, compararia nota[2] com nota[3] e haveria troca ficando nossa matriz assim:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 79 86 68

Agora compararia nota[3] com nota[4] e novamente haveria troca:


nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 79 68 86

Agora, nosso programa iniciaria novo ciclo de comparaes comparando novamente nota[0] com nota[1], nota[1] com nota[2], etc .... at que todos os elementos da matriz estivessem na ordem crescente. Abaixo segue um exerccio que ordena uma matriz de cinco valores inteiros, em ordem crescente, pelo mtodo da bolha:
/* ordenando uma matriz pelo mtodo da bolha * * * neste mtodo a matriz percorrida e os pares

* adjacentes so comparados e ordenados. Isto * feito at que toda a matriz esteja ordenada */ #include <stdio.h> int main() { int vetor[5],contador,ordenados,auxiliar; printf("Ordenando uma matriz utilizando o mtodo da bolha.\n"); /* entrada de dados */ for(contador=0;contador < 5; contador++) { printf("Entre com o %do valor :",(contador+1)); scanf("%d",&vetor[contador]); } /* ordenao */ ordenados = 0; /* indica que os elementos adjacentes no esto ordenados */ while(ordenados == 0) { ordenados = 1; /* considera todos os elementos ordenados corretamente */ for(contador=0;contador < 4;contador++) { /* se os elementos adjacentes no estiverem ordenados executa a troca */ if(vetor[contador] > vetor[(contador + 1)]) { auxiliar = vetor[contador]; vetor[contador] = vetor[(contador + 1)]; vetor[(contador + 1)] = auxiliar; ordenados = 0; /* fora outra passagem no lao while */ } } } /* imprimindo os valores ordenados */ printf("\n"); for(contador=0;contador < 5;contador++) printf("%d ",vetor[contador]); printf("\n"); return(0); }

12.7 Ordenando os elementos de uma matriz pelo mtodo da seleo


Este mtodo tambm s deve ser usado com matrizes pequenas. Neste mtodo o programa procura o menor valor entre todos os elementos da matriz e troca-o pelo primeiro elemento; depois procura o menor entre o segundo e o ltimo elemento da matriz e troca-o pelo segundo elemento; depois procura o menor valor entre o terceiro e o ltimo elemento da matriz e troca-o pelo terceiro, e assim por diante. Vamos ver um exemplo prtico. Dada a matriz:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 67 55 86 79 68

Vamos orden-la em ordem crescente pelo mtodo da seleo: Primeiro nosso programa teria que determinar o menor valor da matriz, que 55 e troc-lo pelo primeiro elemento da matriz (nota [0]). Nossa matriz ficaria assim:

nota[0] nota[1] nota[2] nota[3] nota[4]

= = = = =

55 67 86 79 68

Agora seria determinado o menor valor entre o segundo (nota [1]) e o ltimo elemento (nota [4]), que 67, e este seria trocado com o segundo elemento (nota [1]), ficando a matriz da seguinte maneira:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 86 79 68

Agora seria determinado o menor valor entre o terceiro (nota [2]) e o ltimo elemento (nota [4]), que 68, e este seria trocado com o terceiro elemento (nota [2]). Agora a matriz est assim:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 68 79 86

Agora seria determinado o menor valor entre nota [3] e nota [4](no caso 79) e este valor trocado com o quarto elemento da matriz. E nossa matriz estaria ordenada:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 68 79 86

Abaixo segue um exerccio que ordena uma matriz de cinco valores inteiros, em ordem crescente, pelo mtodo da seleo:
/* ordenando uma matriz pelo mtodo da seleo * * * neste mtodo a ordenao feita da seguinte maneira: * - identifica-se o menor valor da matriz * - troca-se este com o primeiro elemento * - identifica-se o menor valor entre o segundo e o ltimo elemento * - troca-se este com o segundo elemento * - identifica-se o menor valor entre o terceiro e o ltimo elemento * - troca-se este com o terceiro elemento * - identifica-se o menor valor entre o quarto e o ltimo elemento * - troca-se este com o quarto elemento * * e assim por diante, at que toda a matriz esteja ordenada */ #include <stdio.h> int main() { int vetor[5],contador1,contador2,indice_do_menor, menor; printf("Ordenando uma matriz utilizando o mtodo da seleo.\n"); /* entrada de dados */ for(contador1 = 0;contador1 < 5; contador1++) { printf("Entre com o %do valor :",(contador1+1)); scanf("%d",&vetor[contador1]); }

/* ordenao */ for(contador1 = 0;contador1 < 4;contador1++) { indice_do_menor = contador1; menor = vetor[contador1]; /* verificando qual o menor */ for(contador2=(contador1 + 1);contador2 < 5;contador2++) if(vetor[contador2] < menor) { indice_do_menor = contador2; /* executando a troca de valores */ menor = vetor[indice_do_menor]; vetor[indice_do_menor] = vetor[contador1]; vetor[contador1] = menor; } } /* imprimindo os valores ordenados */ printf("\n"); for(contador1 = 0;contador1 < 5;contador1++) printf("%d ",vetor[contador1]); printf("\n"); return(0); }

12.8 Ordenando os elementos de uma matriz pelo mtodo da insero


Neste mtodo, tambm usado com matrizes pequenas, o programa inicialmente ordena os dois primeiros elementos da matriz. Depois insere o terceiro elemento na posio ordenada em relao aos dois primeiros. Depois insere o quarto elemento em sua posio ordenada em relao aos trs j posicionados, e assim por diante at que toda a matriz esteja ordenada. Vamos a um exemplo prtico. Dada nossa matriz:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 67 55 86 79 68

Vamos orden-la em ordem crescente pelo mtodo da insero: Primeiro nosso programa ordenaria os dois primeiros elementos da matriz:
nota[0] = 55 nota[1] = 67

Depois o programa pegaria o terceiro elemento da matriz e o introduziria na posio ordenada em relao aos dois primeiros:
nota[0] = 55 nota[1] = 67 nota[2] = 86

Depois o programa pegaria o quarto elemento da matriz e o introduziria na posio ordenada em relao aos trs primeiros:
nota[0] = 55 nota[1] = 67

nota[2] = 79 nota[3] = 86

Depois o programa pegaria o quinto elemento da matriz e o introduziria na posio ordenada em relao aos quatro primeiros:
nota[0] nota[1] nota[2] nota[3] nota[4] = = = = = 55 67 68 79 86

E nossa matriz estaria ordenada. Abaixo segue um exerccio que ordena uma matriz de cinco valores inteiros, em ordem crescente, pelo mtodo da insero:
/* ordenando uma matriz pelo mtodo da insero * * * neste mtodo a ordenao feita da seguinte maneira: * - os dois primeiros elementos da matriz so ordenados * - o terceiro elemento introduzido em sua posio ordenada em relao aos dois primeiros * - o quarto elemento introduzido em sua posio ordenada em relao aos trs primeiros * - o quinto elemento introduzido em sua posio ordenada em relao aos quatro primeiros * * e assim por diante at que toda a matriz esteja ordenada.*/ #include <stdio.h> int main() { int vetor_original[5], vetor_ordenado[5]; int contador,contador2,contador3; int ok = 0; printf("Ordenando uma matriz utilizando o mtodo da insero.\n"); /* entrada de dados */ for(contador=0;contador < 5; contador++) { printf("Entre com o %do valor :",(contador+1)); scanf("%d",&vetor_original[contador]); } /* ordenao */ /* ordenando os dois primeiros elementos */ if(vetor_original[0] < vetor_original[1]) { vetor_ordenado[0] = vetor_original[0]; vetor_ordenado[1] = vetor_original[1]; } else { vetor_ordenado[0] = vetor_original[1]; vetor_ordenado[1] = vetor_original[0]; } /* ordenando os outros elementos */ for(contador = 2;contador < 5; contador++) { /* introduzindo o elemento vetor_original[contador] no vetor_ordenado */

ok = 1; /* considera vetor_ordenado no ordenado */ /* verificando se algum dos elementos de vetor_ordenado maior que * vetor_original[contador] */ for(contador2 = 0;contador2 < contador;contador2++) { if(vetor_ordenado[contador2] > vetor_original[contador]) { /* jogando os elementos de vetor_ordenado para frente */ for(contador3 = contador;contador3 > contador2;contador3--) vetor_ordenado[contador3] = vetor_ordenado[contador3 - 1]; /* inserindo vetor_original[contador] em sua posio ordenada */ vetor_ordenado[contador2] = vetor_original[contador]; ok =0; /* considerando vetor_ordenado ordenado */ break; } } /* se nenhum elemento de vetor_ordenado maior que vetor_original[contador] ... */ if(ok == 1) vetor_ordenado[contador] = vetor_original[contador]; } /* imprimindo os valores ordenados */ printf("\n"); for(contador = 0;contador < 5;contador++) printf("%d ",vetor_ordenado[contador]); printf("\n"); return(0); }

12.9 Ordenando os elementos de uma matriz pelo mtodo shell


Este mtodo de ordenao oferece uma performance bem melhor que os anteriormente mostrados. Nele compara-se elementos separados por uma distncia especfica ordenando-os. Esta distncia ento dividida por dois e o processo continua at que a matriz esteja ordenada. Vamos ao nosso exemplo prtico com a matriz:
nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] = = = = = = = = = = 67 55 86 79 68 99 0 34 18 27

Nossa matriz tem dez elementos. Vamos comear nossa ordenao ordenando os elementos separados de cinco posies. Ento compararemos nota[0] e nota[5]. Como estes elementos esto ordenados, nosso programa nada faria. Agora sero comparados nota[1] e nota[6]. Como esto fora de ordem, sero ordenados e nossa matriz ficar assim:
nota[0] = 67 nota[1] = 0 nota[2] = 86

nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9]

= = = = = = =

79 68 99 55 34 18 27

Agora nota[2] e nota[7]. Como esto desordenados, haver ordenao e a matriz ficar assim:
nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] = = = = = = = = = = 67 0 34 79 68 99 55 86 18 27

Agora nota[3] e nota[8]:


nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] = = = = = = = = = = 67 0 34 18 68 99 55 86 79 27

E nota[4] com nota[9]:


nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] = = = = = = = = = = 67 0 34 18 27 99 55 86 79 68

Terminado este ciclo de comparaes a nossa distncia ser dividida por dois, sendo agora igual a trs, j que devemos usar nmeros inteiros para definir esta distncia. Agora vamos a outro ciclo de comparaes, s que desta vez com os elementos separados por trs posies. Iniciando com a comparao de nota[0] e nota[3], haveria ordenao e nossa matriz agora ficar assim:
nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] = = = = = = = = = = 18 0 34 67 27 99 55 86 79 68

Agora nota[1] com nota[4], como esto ordenados no h nenhuma mudana. Agora nota[2] com nota[5], tambm sem mudanas.
nota[3] nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9]

com nota[6]. Esto desordenados. Nossa matriz agora ficar assim:


= = = = = = = = = = 18 0 34 55 27 99 67 86 79 68

Agora nota[4] com nota[7]. Como os elementos esto ordenados, no h mudanas.


nota[5] nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9]

com nota[8] esto desordenados, ento haver reordenao:


= = = = = = = = = = 18 0 34 55 27 79 67 86 99 68

E terminando este ciclo a comparao de nota[6] com nota[9] no alterar a matriz pois os elementos esto ordenados. Agora a distncia novamente dividia por dois e nossa nova distncia ser dois, pois no podemos usar a distncia 1,5. Abaixo temos as comparaes deste novo ciclo;
nota[0] nota[1] nota[2] nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9] nota[3] nota[4]

com nota[2] => esto ordenados, matriz inalterada. com nota[3] => esto ordenados, matriz inalterada. com nota[4] => esto desordenados, a matriz fica assim:
= = = = = = = = = = 18 0 27 55 34 79 67 86 99 68

com nota[5] => esto ordenados, matriz inalterada. com nota[6] => esto ordenados, matriz inalterada.

nota[5] nota[6] nota[7] nota[0] nota[1] nota[2] nota[3] nota[4] nota[5] nota[6] nota[7] nota[8] nota[9]

com nota[7] => esto ordenados, matriz inalterada. com nota[8] => esto ordenados, matriz inalterada. com nota[9] => esto desordenados, a matriz fica assim:
= = = = = = = = = = 18 0 27 55 34 79 67 68 99 86

E agora o ciclo final. Dividindo nossa distncia atual (2) por dois teremos a comparao dos elementos separados por uma posio.E ao final deste ciclo nossa matriz estaria ordenada. O nico detalhe a ser observado evitar sequncias de distncias que so potncia de dois, pois elas reduzem a eficincia deste algoritmo.Por exemplo: a sequncia "8,4,2,1" no interessante,seria melhor "7,3,2,1". Abaixo segue uma codificao deste exemplo:
/* ordenando uma matriz pelo mtodo shell * * * neste mtodo a ordenao feita da seguinte maneira: * - compara-se os elementos separados por uma distncia especfica * - divide-se esta distncia por dois * - compara-se os elementos separados pela nova distncia * - divide-se a distncia por dois novamente * e assim por diante, at que toda a matriz esteja ordenada */ #include <stdio.h> int main() { int QDE = 10; int vetor[QDE],contador1,contador2,distancia,auxiliar; printf("Ordenando uma matriz utilizando o mtodo shell.\n"); /* entrada de dados */ for(contador1 = 0;contador1 < QDE; contador1++) { printf("Entre com o %do valor :",(contador1+1)); scanf("%d",&vetor[contador1]); } /* ordenao */ distancia = QDE; do { distancia = (distancia + 1) / 2; for(contador2 = 0;contador2 < (QDE - distancia); contador2++) { if(vetor[contador2] > vetor[contador2 + distancia]) { auxiliar = vetor[contador2 + distancia]; vetor[contador2 + distancia] = vetor[contador2]; vetor[contador2] = auxiliar; }

} } while (distancia > 1); /* imprimindo os valores ordenados */ printf("\n"); for(contador1 = 0;contador1 < QDE;contador1++) printf("%d ",vetor[contador1]); printf("\n"); return(0); }

12.10 Ordenando os elementos de uma matriz pelo mtodo quick sort


Para matrizes com muitos elementos este o mtodo de ordenao mais rpido. Neste tipo de ordenao o programa considera sua matriz uma lista de valores. Inicialmente selecionado o valor que est posicionado no meio da lista que chamaremos de elemento central. Depois a matriz dividida e ordenada em duas listas menores separando numa os elementos cujo valor maior que o valor do elemento central e e na outra os elementos cujo valor menor que o valor do elementro central. A partir da o mesmo processo feito com cada uma das listas recursivamente. Isso continua at que a matriz esteja toda ordenada. Considere a matriz formada pelos valores inteiros: 6, 2, 1, 3, 4, 5, 8, 7 e 0. A figura abaixo mostra como poderamos classificar esta matriz em ordem crescente usando o quick sort.

Abaixo segue o exemplo de um cdigo que ordena em ordem crescente, pelo mtodo quick sort, uma matriz de valores inteiros:
/* ordenando uma matriz pelo mtodo quick sort */ #include <stdio.h> void quick_sort(int matriz[], int primeiro, int ultimo) { int temp, baixo,alto,separador; baixo = primeiro; alto = ultimo; separador = matriz[(primeiro + ultimo) / 2]; do { while(matriz[baixo] < separador) baixo++; while(matriz[alto] > separador) alto--; if(baixo <= alto)

{ temp = matriz[baixo]; matriz[baixo++] = matriz[alto]; matriz[alto--] = temp; } } while(baixo <= alto); if(primeiro < alto) quick_sort(matriz,primeiro,alto); if(baixo < ultimo) quick_sort(matriz,baixo,ultimo); } int main() { int QDE = 10; int vetor[QDE],contador; printf("Ordenando uma matriz utilizando o mtodo quick sort.\n"); /* entrada de dados */ for(contador = 0;contador < QDE; contador++) { printf("Entre com o %do valor :",(contador+1)); scanf("%d",&vetor[contador]); } quick_sort(vetor,0,(QDE-1)); /* imprimindo os valores ordenados */ printf("\n"); for(contador = 0;contador < QDE;contador++) printf("%d ",vetor[contador]); printf("\n"); return(0); }

13. Ponteiros 13.1 Exibindo o endereo de memria de uma varivel


Para exibir o endereo de memria de uma varivel use o operador & antes da varivel. Lembre-se que o valor da varivel uma coisa e o endereo de memria onde este valor est armazenado outra. O cdigo abaixo esclarecer melhor estes conceitos:
/* exibindo o endereo de memria de variveis */ #include <stdio.h> int main() { char letra = 's'; int idade = 35; char nome[10] = "samuel"; float peso = 87.8; float altura = 1.82; printf("Exibindo o printf("O valor da printf("O valor da printf("O valor da printf("O valor da printf("O valor da endereo varivel varivel varivel varivel varivel de memria de variveis\n\n"); letra %c e seu endereo %x\n",letra,&letra); idade %d e seu endereo %x\n",idade,&idade); nome %s e seu endereo %x\n",nome,nome); peso %2.1f e seu endereo %x\n",peso,&peso); altura %1.2f e seu endereo %x\n",altura,&altura);

Ao ser executado, o cdigo acima dever exibir algo parecido com:


Exibindo o endereo de memria de variveis O O O O O valor valor valor valor valor da da da da da varivel varivel varivel varivel varivel letra s e seu endereo bffff8cb idade 35 e seu endereo bffff8c4 nome samuel e seu endereo bffff8b8 peso 87.8 e seu endereo bffff8b4 altura 1.82 e seu endereo bffff8b0

Observe na codificao que a varivel nome no precisou do operador de endereo & pois matrizes j so tratadas como ponteiros pela linguagem C. Assim, quando o programa passa uma matriz para uma funo, o compilador passa o endereo inicial da matriz.

13.2 Definio de ponteiros


Depois de entendida a diferena entre o valor de uma varivel e seu endereo de memria fica fcil definir ponteiros. Ponteiro uma varivel que armazena um endereo de memria. OBSERVAO:Cabe aqui ressaltar que a linguagem C trata as matrizes como ponteiros, assim quando seu programa passa uma matriz para uma funo, o compilador na verdade passa o endereo do primeiro elemento da matriz. Observe o exemplo abaixo:
/* verificando como C trata as matrizes como ponteiros */ #include <stdio.h> int main() { int idade[5]; float peso[5]; char nome[10] = "samuel"; printf("O endereo do primeiro elemento da matriz idade %x\n",idade); printf("O endereo do primeiro elemento da matriz peso %x\n",peso); printf("O endereo do primeiro elemento da matriz nome %x\n",nome); return(0); }

13.3 Declarando uma varivel ponteiro


A sintaxe para a declarao de uma varivel ponteiro :
TIPO *NOME

onde TIPO um tipo de dados vlido e NOME o nome da varivel. Exemplo:


int *idade;

13.4 Atribuindo valor a uma varivel ponteiro


Como o ponteiro uma varivel que armazena um endereo de memria, voc dever atribuir a uma varivel ponteiro um endereo de memria. Exemplo:

/* atribuindo valor a uma varivel ponteiro */ #include <stdio.h> int main() { int idade = 35; int *ptr_idade; ptr_idade = &idade; /* foi atribudo o endereo da varivel idade a varivel ponteiro ptr_idade. Observe o uso do operador & que devolve o endereo de memria da varivel idade. */ printf("O valor da varivel idade %d\n",idade); printf("O endereo da varivel idade %x\n",&idade); printf("O valor da varivel ponteiro ptr_idade %x\n",ptr_idade); return(0); }

13.5 Desreferenciando um ponteiro


Um ponteiro armazena um endereo de memria. Desreferenciar um ponteiro acessar o valor armazenado neste endereo. Para isso voc deve usar o operador de indireo, que o asterisco * . Exemplo:
/* desreferenciando um ponteiro */ #include <stdio.h> int main() { int idade = 35; int *ptr_idade; ptr_idade = &idade; /* foi atribudo o endereo da varivel idade a varivel ponteiro ptr_idade. Observe o uso do operador & que devolve o endereo de memria da varivel idade. */ printf("O valor da varivel idade %d\n",idade); printf("O endereo da varivel idade %x\n",&idade); printf("O valor da varivel ponteiro ptr_idade %x\n",ptr_idade); printf("O valor apontado por ptr_idade %d\n",*ptr_idade); /* observe, na linha acima, o uso do operador de indireo ( * ) * para desreferenciar o ponteiro ptr_idade e, assim, exibir * o valor armazenado no endereo de memria apontado por ele. */ return(0); }

13.6 Alterando o valor armazenado no endereo apontado por um ponteiro


/* Alterando o valor armazenado no endereo apontado * por um ponteiro */ #include <stdio.h> int main() { int numero = 35; int *ptr;

ptr = &numero; /* atribuindo o endereo de numero a ptr */ printf("O ponteiro ptr armazena o endereo %x que,\npor sua vez,\ armazena o valor %d\n",ptr,*ptr); *ptr = 25; /* alterando o valor armazenado no endereo * apontado por ptr. Observe que o ponteiro * deve ser desreferenciado.*/ printf("\nAgora o ponteiro ptr armazena o endereo %x que,\npor sua vez,\ armazena o valor %d\n",ptr,*ptr); return(0); }

13.7 Ponteiros como parmetros de funo


Quando queremos alterar o valor dos argumentos passados para uma funo devemos definir os parmetros da funo como ponteiros. A isso denominamos chamada por referncia. Exemplo:
/* ponteiros como parmteros de funo */ #include <stdio.h> /* a funo que recebe como argumento o valor * da varivel no consegue alterar o valor * deste */ int valor(int a) { a = 35; /* alterando o valor do argumento passado */ } /* a funo que recebe como argumento um ponteiro * consegue alterar o valor apontado por este */ int ponteiro(int *a) { *a = 35; /* alterando o valor do argumento passado */ }

int main() { int nr = 26; int *ptr_nr; printf("O valor inicial de nr %d\n",nr); valor(nr); /* funo que recebe o valor. No consegue alterar este */ printf("Valor de nr aps a chamada da funo valor = %d\n",nr); ptr_nr = &nr; ponteiro(ptr_nr); /* funo que recebe ponteiro. Consegue alterar valor * apontado */ printf("Valor de nr aps a chamada da funo ponteiro = %d\n",nr); return(0); }

13.8 Aritmtica dos ponteiros


Voc pode somar e subtrair valores a ponteiros, porm deve estar atento a um detalhe. Os ponteiros so endereos de memria, assim ao somar 1 a um ponteiro voc estar indo para o prximo endereo de

memria do tipo de dado especificado. Por exemplo, digamos que um ponteiro do tipo char aponta para o endereo 1000. Se voc somar 2 a este ponteiro o resultado ser um ponteiro apontando para o endereo 1002, pois o tipo char requer um byte de memria para armazenar seus dados. Se este ponteiro fosse do tipo int o resultado seria um ponteiro apontando para o endereo 1008, pois o tipo int, sob o linux, requer quatro bytes para armazenar seus dados. Ento, sempre que for somar ou subtrair aos ponteiros voc tem que trabalhar com o tamanho do tipo de dado utilizado. Para isso voc pode usar o operador sizeof. Analise o cdigo abaixo para um melhor entendimento deste conceito:
/* visualizando como funciona a aritmtica de ponteiros */ #include <stdio.h> int main() { char letra[5] = {'a','e','i','o','u'}; int contador, nr[5] = {30,12,67,13,41}; char *ptr_letra; int *ptr_nr; ptr_letra = letra; ptr_nr = nr; printf("Visualizando como funciona a aritmtica de ponteiros\n"); printf("\nmatriz letra = a, e, i, o, u\n"); printf("matriz nr = 30,12,67,13,41\n"); printf("\nVerificando o tamanho dos tipos de dados\n"); printf("tamanho do tipo de dado char = %d\n",sizeof(char)); printf("tamanho do tipo de dado int = %d\n",sizeof(int)); printf("\nPonteiro para letra aponta para %c no endereo %x\n",*ptr_letra,ptr_letra); printf("Ponteiro para nr aponta para %d no endereo %x\n",*ptr_nr,ptr_nr); printf("\nIncrementando os ponteiros\n"); printf("ptr_letra + 3, ptr_nr + 2\n"); ptr_letra += 3; ptr_nr += 2; printf("\nPonteiro para letra agora aponta para %c no endereo %x\n",*ptr_letra,ptr_letra); printf("Ponteiro para nr agora aponta para %d no endereo %x\n",*ptr_nr,ptr_nr); return(0); }

13.9 Exibindo uma string usando um ponteiro


Uma string uma matriz de caracteres. Podemos usar um ponteiro para exib-la assim:
/* exibindo uma string usando um ponteiro */ #include <stdio.h> int main() { char string[40] = "Exibindo uma string usando um ponteiro."; char *ptr_str; /* Apontando para a string */

ptr_str = string; printf("Apontando para o inicio da string => ptr_str = %c\n\n",*ptr_str); /* Exibindo toda a string usando o ponteiro */ while(*ptr_str) { putchar(*ptr_str); ptr_str++; } printf("\n"); return(0); }

13.10 Criando uma funo que retorna um ponteiro


#include <stdio.h> #include <ctype.h> /* Funo que converte uma strig para maisculas. * Esta funo retorna um ponteiro */ char *converte_maiuscula(char *string) { char *inicio_da_str, *auxiliar; inicio_da_str = auxiliar = string; while(*string) { *auxiliar = toupper(*string); string++; auxiliar++; } return(inicio_da_str); }

int main() { char string[80] = "Usando uma funo que retorna uma string."; printf("%s\n",string); converte_maiuscula(string); printf("%s\n",string); return(0); }

13.11 Matriz de ponteiros/strings


A linguagem C lhe permite criar matrizes de ponteiros. O uso mais comum para este tipo de matriz conter strings. Abaixo segue um exemplo da declarao de uma matriz que armazena ponteiros para strings:
char *dias(7) = {"Domingo","Segunda","Tera","Quarta","Quinta","Sexta","Sbado"};

OBSERVAO:Em matrizes de ponteiros para strings a linguagem C no inclui um item NULL para indicar o final da matriz, voc tem que fazer isso.

13.12 Percorrendo uma matriz de strings com um lao for


/* percorrendo uma matriz de strings com um lao for */ #include <stdio.h> int main()

{ char *dias[7] = {"Domingo","Segunda","Tera","Quarta","Quinta","Sexta","Sbado"}; int contador; for(contador = 0;contador < 7;contador++) printf("%do dia da semana = %s\n",contador+1,dias[contador]); return(0); }

13.13 Percorrendo uma matriz de strings com um ponteiro


/* percorrendo uma matriz de strings com um ponteiro */ #include <stdio.h> int main() { char *dia[] = {"Domingo","Segunda","Tera","Quarta","Quinta","Sexta","Sbado",0}; char **ptr_dia; /* *dia um ponteiro para uma string e * **ptr_dia um ponteiro para um ponteiro para uma string */ ptr_dia = dia; /* apontando ptr_dia para o incio da matriz dia */ while(*ptr_dia) { printf("%s\n",*ptr_dia); ptr_dia++; } return(0); } /* Quando voc declara uma matriz de strings o compilador * no acrescenta um caractere NULL para indicar o final * da matriz como o faz com uma matriz de caracteres (strings). * Por isso voc mesmo tem que inserir o caractere NULL para * indicar o final da matriz. * * Foi isso que foi feito ao inserir 0 no final da matriz dia */

13.14 Ponteiro para funo


Voc pode criar um ponteiro para uma funo. O uso mais comum deste recurso para passar uma funo como parmetro para outra funo. A declarao de um ponteiro para uma funo segue a sintaxe:
TIPO (*FUNO)();

Observe o uso disto no exemplo abaixo:


/* exemplificando o uso de ponteiro para uma funo */ #include <stdio.h> /* funo que identifica o maior entre dois inteiros */ int maior(int nr1,int nr2) { return((nr1 > nr2) ? nr1 : nr2); } /* funo usa_maior(). Recebe dois inteiros e um

* ponteiro para a funo maior() */ int usa_maior(int x,int y, int (*maior)()) { return(maior(x,y)); } int main() { int a,b; printf("Entre com o primeiro nmero: "); scanf("%d",&a); printf("Entre com o segundo nmero: "); scanf("%d",&b); printf("O maior entre os dois %d\n",usa_maior(a,b,&maior)); /* observe logo acima que usa_maior() recebe como argumentos * dois nmeros inteiros e o endereo da funo maior() * sendo, assim, coerente com sua declarao */ return(0); }

14. Estruturas
As estruturas so utilizadas para agrupar informaes relacionadas de tipos de dados diferentes. Digamos que voc precisa controlar os seguintes dados relacionados ao estoque de um pequeno estabelecimento comercial:

cdigo nome do produto quantidade estocada valor de compra valor a ser vendido lucro observaces sobre o produto

Este seria um caso para o uso de estruturas, pois relacionados a cada produto teremos dados do tipo int(cdigo,quantidade), char(nome, observaes) e float(valor de compra, valor de venda, lucro).

<>14.1 Declarando uma estrutura


A sintaxe para a declarao (ou criao) de uma estrutura :
struct NOME_DA_ESTRUTURA { TIPO CAMPO1; TIPO CAMPO2; ........... ........... TIPO CAMPOn; };

Para o caso exemplificado no item anterior poderamos ter algo como:


struct produto { int codigo; char nome[50]; int quantidade; float valor_compra;

float valor_venda; float lucro; char obs[200]; };

importante observar que a declarao da estrutura no cria, ainda, uma varivel. A declarao da estrutura apenas cria um novo tipo de dado. Aps criar a estrutura voc pode declarar variveis do tipo de estrutura criado.

<>14.2 Declarando variveis do tipo de uma estrutura criada


Aps a declarao da estrutura voc pode declarar variveis do tipo da estrutura com a sintaxe:
struct NOME_DA_ESTRUTURA NOME_DA_VARIVEL;

Exemplo:
struct produto item;

Observe que esta sintaxe obecede a sintaxe normal para a declarao de variveis:
TIPO NOME_DA_VARIVEL;

sendo o TIPO da varivel, a nova estrutura criada ( struct NOME_DA_ESTRUTURA ). Voc tambm pode declarar a varivel logo aps a declarao da estrutura com uma sintaxe do tipo:
struct produto { int codigo; char nome[50]; int quantidade; float valor_compra; float valor_venda; float lucro; char obs[200]; }item;

<>14.3 Acessando os campos de uma estrutura


A sintaxe para acessar e manipular campos de estruturas a seguinte:
NOME_DA_ESTRUTURA.CAMPO

Observe o cdigo abaixo para um melhor esclarecimento:


/* acessando os campos de uma estrutura */ #include <stdio.h> /* criando um novo tipo de dado "produto" */ struct produto { int codigo; char nome[50]; int quantidade; float valor_compra; float valor_venda; };

int main() { struct produto item; /* declarando uma varivel "item" do tipo "struct produto" */ printf("Preenchendo a varivel \"item\"\n"); printf("Item............:"); fgets(item.nome,50,stdin); printf("Cdigo..........:"); scanf("%d",&item.codigo); printf("Quantidade......:"); scanf("%d",&item.quantidade); printf("Valor de compra.:"); scanf("%f",&item.valor_compra); printf("Valor de revenda:"); scanf("%f",&item.valor_venda); printf("\n"); printf("Exibindo os dados\n"); printf("Cdigo..........:%d\n",item.codigo); printf("Item............:%s",item.nome); printf("Quantidade......:%d\n",item.quantidade); printf("Valor de compra.:%.2f\n",item.valor_compra); printf("Valor de revenda:%.2f\n",item.valor_venda); return(0); }

<>14.4 Acessando uma estrutura com ponteiros


Para acessar uma estrutura usando ponteiros voc pode usar duas sintaxes:
(*NOME_DA_ESTRUTURA).CAMPO

ou
NOME_DA_ESTRUTURA->CAMPO

Exemplo:
/* acessando uma estrutura com ponteiros */ #include <stdio.h> struct registro { char nome[30]; int idade; };

altera_estrutura1(struct registro *ficha) { (*ficha).idade -= 10; } altera_estrutura2(struct registro *ficha) { ficha->idade += 20; } int main() { struct registro ficha; printf("Entre com seu nome:"); fgets(ficha.nome,30,stdin);

printf("Qual sua idade?"); scanf("%d",&ficha.idade); printf("\nExibindo os dados iniciais\n"); printf("Nome: %s",ficha.nome); printf("Idade: %d.\n",ficha.idade); altera_estrutura1(&ficha); printf("\nExibindo os dados aps a primeira alterao\n"); printf("Nome: %s",ficha.nome); printf("Idade: %d.\n",ficha.idade); altera_estrutura2(&ficha); printf("\nExibindo os dados aps a segunda alterao\n"); printf("Nome: %s",ficha.nome); printf("Idade: %d.\n",ficha.idade); return(0); }

15. Gerenciamento de memria <>15.1 Preenchendo um intervalo de memria com uma constante byte
Para preencher um intervalo de memria utilize a funo memset() . No gcc ela faz parte do arquivo de cabealho string.h e sua sintaxe :
*memset(*STRING,CARACTER,BYTES)

a funo acima preenche BYTES da rea de memria apontada por *STRING com CARACTER . A funo retorna um ponteiro para *STRING . Ao preencher strings com esta funo, pelo menos no ambiente Linux usando o gcc, a funo no inseriu o caracter NULL para indicar o final da string, assim tive que fazer isso eu mesmo. Exemplo:
/* preechendo uma rea de memria usando a funo memset() */ #include <stdio.h> #include <string.h> int main() { char nome[10]; memset(nome,'s',10); nome[10] = 0; /* inserindo o valor NULL para indicar o final da string */ printf("%s\n",nome); return(0); }

<>15.2 Copiando um intervalo de memria


Para copiar um intervalo de memria use a funo memcpy() . Ela faz parte do arquivo de cabealho string.h e sua sintaxe :
*memcpy(*DESTINO,*ORIGEM,BYTES)

a funo acima copia BYTES da rea de meria *ORIGEM para a rea de memria *DESTINO . A funo retorna um ponteiro para *DESTINO . Exemplo:
/* copiando um intervalo de memria */ #include <stdio.h> #include <string.h> int main() { float nrs1[5] = {1.1,1.2,1.3,1.4,1.5}; float nrs2[5] = {5,5,5,5,5}; int contador; printf("valores de nrs1\n"); for(contador = 0;contador < 5;contador++) printf("%.1f ",nrs1[contador]); printf("\n"); printf("valores de nrs2 inicialmente\n"); for(contador = 0;contador < 5;contador++) printf("%.1f ",nrs2[contador]); printf("\n"); memcpy(nrs2,nrs1,sizeof(nrs1)); /* observe o uso do operador "sizeof" para * determinar o tamanho da rea de memria * a ser copiada */ printf("valores de nrs2 aps a cpia\n"); for(contador = 0;contador < 5;contador++) printf("%.1f ",nrs2[contador]); printf("\n"); return(0); }

<>15.3 Movendo um intervalo de memria


Para mover uma rea de memria use a funo memmove() que est no arquivo de cabealho string.h . Sua sintaxe :
*memmove(*DESTINO,*ORIGEM,BYTES)

a funo acima move BYTES da rea de memria *ORIGEM para a rea de memria *DESTINO . A funo retorna um ponteiro para *DESTINO . A diferena entre esta funo e a funo memcpy() mostrada na seo anterior que com esta as rea de memria *DESTINO e *ORIGEM podem se sobrepor. Exemplo:
/* movendo um intervalo de memria */ #include <stdio.h> #include <string.h> int main() { float nrs[5] = {1.1,1.2,1.3,1.4,1.5}; float *ptr_nrs; int contador,bytes; printf("valores de nrs inicialmente\n"); for(contador = 0;contador < 5;contador++) printf("%.1f ",nrs[contador]); printf("\n");

ptr_nrs = nrs; ptr_nrs++; bytes = (sizeof(float) * 4); memmove(nrs,ptr_nrs,bytes); printf("valores de nrs aps a movimentao\n"); for(contador = 0;contador < 5;contador++) printf("%.1f ",nrs[contador]); printf("\n"); return(0); }

<>15.4 Copiando at encontrar um byte especfico


Usando a funo memccpy() , que est no arquivo de cabealho string.h voc pode copiar um intervalo de memria at encontrar um byte especfico. A sintaxe da funo ;
*memccpy(*DESTINO,*ORIGEM,CARACTER,BYTES)

Ela copia, no mximo, BYTES de *ORIGEM para *DESTINO , parando se CARACTER for encontrado. Ela retorna um ponteiro para o prximo byte aps CARACTER em *DESTINO ou NULL se CARACTER no for encontrado nos primeiros BYTES de *ORIGEM . Exemplo:
/* copiando um intervalo de memria at encontrar um * byte especfico */ #include <stdio.h> #include <string.h> int main() { char frase[80] = "E como dizia meu velho professor de fsica...estudem!!!"; char copia[80]; char *ptr_copia; /* "ptr_copia" aponta para o resultado de memccpy(). * Se o caracter "." for encontrado em "frase", * ser efetuada a cpia da rea de memria at * este caracter e "ptr_copia" apontar para o * prximo byte aps "." em "copia. * Caso contrrio, sero copiados 80 bytes e * "ptr_copia" receber o valor NULL. */ ptr_copia = memccpy(copia,frase,'.',80); if(ptr_copia) *ptr_copia = 0; printf("%s\n",copia); return(0); }

<>15.5 Comparando duas reas de memria


Voc pode comparar duas reas de memria usando a funo memcmp() . Ela faz parte do arquivo de cabealho string.h e sua sintaxe :
memcpy(*AREA1,*AREA2,BYTES)

Ela compara os primeiros BYTES de *AREA1 e *AREA2 .Se *AREA1 for maior ela retorna um inteiro maior que zero, se *AREA2 for maior ela retorna um inteiro menor que zero e caso as duas reas sejam iguais ela retorna zero. Exemplo:
/* comparando duas reas de memria */ #include <stdio.h> #include <string.h> int main() { char string1[7] = "aeiou"; char string2[7] = "Aeiou"; int resultado; printf("string1 = %s\n",string1); printf("string2 = %s\n\n",string2); resultado = memcmp(string1,string2,7); if(resultado > 0) printf("string1 else if(resultado printf("string2 else printf("string1 return(0); } /* Faa algumas substituies no cdigo * trocando o "A" maisculo de "string2" * para "string1" e/ou substituindo-o * por um "a" e observe os vrios * resultados do programa. */

maior\n"); < 0) maior\n"); e string2 so iguais\n");

<>15.6 Trocando bytes adjacentes


Quando voc precisar trocar os bytes adjacentes, normalmente para trocar dados entre mquinas que possuem ordenamento de bytes alto/baixo diferentes, use a funo swab() . Ela faz parte do arquivo de cabealho string.h e sua sintaxe :
swab(*ORIGEM,*DESTINO,BYTES)

Ela copia BYTES de *ORIGEM para *DESTINO trocando os bytes adjacentes, pares e mpares. Exemplo:
/* trocando bytes adjacentes */ #include <stdio.h> #include <string.h> int main() { char str_origem[30] = "Trocando bytes adjacentes"; char str_destino[30]; memset(str_destino,'s',30); str_destino[30] = 0; printf("str_origem => %s\n",str_origem); printf("str_destino => %s\n",str_destino);

printf("chamando swab()\n"); swab(str_origem,str_destino,30); printf("str_origem => %s\n",str_origem); printf("str_destino => %s\n",str_destino); return(0); }

<>15.7 Alocando memria dinamicamente


Quando voc declara uma matriz o compilador aloca memria para o armazenamento dos dados desta matriz. Caso voc queira alterar o tamanho da matriz ter que modificar o cdigo e recompilar o programa. Para evitar isso voc pode alocar memria dinamicamente, ou seja, o programa aloca a memria necessria durante a execuo. Para isso voc pode usar as funes calloc() e malloc() . Em ambiente linux, usando o gcc, elas fazem parte do arquivo de cabealho stdlib.h . A sintaxe de calloc() :
*calloc(QUANTIDADE_DE_ELEMENTOS,TAMANHO)

Ela aloca memria para uma matriz com o nmero de elementos igual a QUANTIDADE_DE_ELEMENTOS , tendo cada um destes elementos TAMANHO bytes. Esta funo retorna um ponteiro para o nicio do bloco de memria alocado ou NULL caso ocorra algum problema. Exemplo do uso de calloc() :
/* alocando memria dinamicamente com calloc() */ #include <stdio.h> #include <stdlib.h> int main() { int *matriz1; int nr_elementos_matriz1; int contador; printf("Alocando memria dinamicamente usando calloc()\n"); printf("Entre com a quantidade de elementos da matriz de inteiros :"); scanf("%d",&nr_elementos_matriz1); matriz1 = (int *) calloc(nr_elementos_matriz1,sizeof(int)); /* Observe acima a instruo "(int *)". Isto usado * para converter o ponteiro retornado por calloc() * para um ponteiro do tipo desejado. Caso voc * estivesse alocando memria para um ponteiro de * ponto flutuante esta instruo seria "(float *"). */ if(matriz1) { for(contador = 0;contador < nr_elementos_matriz1;contador++) { printf("Entre com o %do elemento :",contador + 1); scanf("%d",&matriz1[contador]); } printf("\n");

for(contador = 0;contador < nr_elementos_matriz1;contador++) printf("Exibindo o %do elemento : %d\n",contador + 1,matriz1[contador]); } else printf("Erro ao alocar memria.\n"); return(0); }

A sintaxe de malloc() :
*malloc(BYTES)

Esta funo aloca BYTES e retorna um ponteiro para o incio da memria alocada ou NULL caso ocorra algum problema. Exemplo do uso de malloc() :
/* alocando memria dinamicamente com malloc() */ #include <stdio.h> #include <stdlib.h> int main() { int *matriz1; int contador; int nr_elementos_matriz1; printf("Alocando memria dinamicamente usando malloc()\n"); printf("Entre com a quantidade de elementos da matriz de inteiros :"); scanf("%d",&nr_elementos_matriz1); matriz1 = (int *) malloc(nr_elementos_matriz1 * sizeof(int)); /* Observe acima a instruo "(int *)". Isto usado * para converter o ponteiro retornado por malloc() * para um ponteiro do tipo desejado. Caso voc * estivesse alocando memria para um ponteiro de * ponto flutuante esta instruo seria "(float *"). */ if(matriz1) { for(contador = 0;contador < nr_elementos_matriz1;contador++) { printf("Entre com o %do elemento :",contador + 1); scanf("%d",&matriz1[contador]); } printf("\n"); for(contador = 0;contador < nr_elementos_matriz1;contador++) printf("Exibindo o %do elemento : %d\n",contador + 1,matriz1[contador]); } else printf("Erro ao alocar memria.\n"); return(0); }

<>15.8 Liberando memria


Quando seu programa no precisar mais da memria alocada com as funes malloc() e calloc() ele deve liberar a memria. Para isso voc pode usar a funo free() , que pertence ao arquivo de cabealho stdlib.h e cuja sintaxe :
free(*PONTEIRO)

Exemplo do uso de free() :


/* liberando memria anteriormente alocada */ #include <stdio.h> #include <stdlib.h> int main() { int *matriz1; int contador; int nr_elementos_matriz1; printf("Alocando memria dinamicamente usando malloc()\n"); printf("e liberando a memria alocada com free()\n"); printf("Entre com a quantidade de elementos da matriz de inteiros :"); scanf("%d",&nr_elementos_matriz1); matriz1 = (int *) malloc(nr_elementos_matriz1 * sizeof(int)); if(matriz1) { for(contador = 0;contador < nr_elementos_matriz1;contador++) { printf("Entre com o %do elemento :",contador + 1); scanf("%d",&matriz1[contador]); } printf("\n"); for(contador = 0;contador < nr_elementos_matriz1;contador++) printf("Exibindo o %do elemento : %d\n",contador + 1,matriz1[contador]); free(matriz1); /* liberando a memria alocada */ } else printf("Erro ao alocar memria.\n"); return(0); }

<>15.9 Alterando o tamanho da memria alocada


Para alterar o tamanho de um bloco de memria anteriormente alocado use a funo realloc() . Ela faz parte do arquivo de cabealho stdlib.h e sua sintaxe :
*realloc(*PONTEIRO,BYTES)

Ela altera o tamanho do bloco apontado por *PONTEIRO para BYTES . A memria recm-alocada no ser inicializada. Se *PONTEIRO for NULL, a chamada ser equivalente a malloc(BYTES) ; se BYTES for igual a zero, a chamada ser equivalente a free(*PONTEIRO) . A menos que *PONTEIRO seja NULL, ele precisa ter sido retornado por uma chamada anterior para malloc() , calloc() ou realloc() .

Exemplo do uso de realloc() :


/* alterando um bloco de memria anteriormente alocado */ #include <stdio.h> #include <stdlib.h> int main() { char *frase; frase = (char *) malloc(10); if(frase) printf("10 bytes alocados com sucesso\n"); else printf("Erro ao alocar memria\n"); printf("\n"); realloc(frase,1000); if(frase) printf("1000 bytes alocados com sucesso\n"); else printf("Erro ao alocar memria\n"); return(0); }

16. Argumentos da linha de comando


Seu programa C pode manipular os argumentos passados na linha de comando. Para isso existem dois parmetros da funo main() . Um o parmetro argc . Ele recebe o nmero de argumentos passados na linha de comando, incluindo o nome do programa. O segundo argv . Este uma matriz de ponteiros para strings que armazena ponteiros que apontam para cada um dos argumentos passados. Para um melhor entendimento observe o cdigo abaixo:
/* entendendo os argumentos da linha de comando */ #include <stdio.h> /* "argc" armazena o nmero de argumentos passados * na linha de comando, incluindo o nome do programa. * "argv" uma matriz de ponteiros para strings e * armazena ponteiros que apontam para cada um * dos argumentos passados para a linha de comando. */ int main(int argc, char *argv[]) { int contador; printf("Foram passados %d argumentos na linha de comando.\n",argc); for(contador = 0;contador < argc;contador++) printf("%do argumento => %s\n",contador,argv[contador]); return(0); }

Compilei o cdigo acima com o nome de args . Observe abaixo como ficou uma sesso de execuo deste programa:
[samu@pitanga c]$ ./args argumento1 argumento2

Foram passados 3 argumentos na linha de comando. 0o argumento => ./args 1o argumento => argumento1 2o argumento => argumento2 [samu@pitanga c]$

Caso o argumento a ser passado seja uma frase voc deve coloc-lo entre aspas. Observe:
[samu@pitanga c]$ ./args "este o primeiro argumento" argumento2 argumento3 Foram passados 4 argumentos na linha de comando. 0o argumento => ./args 1o argumento => este o primeiro argumento 2o argumento => argumento2 3o argumento => argumento3 [samu@pitanga c]$

Voc pode ainda manipular argv como ponteiro em vez de trat-lo como uma matriz de strings. Para isso voc deve declar-lo como um ponteiro para um ponteiro de strings. Exemplo:
/* tratando "argv" como ponteiro */ #include <stdio.h> /* observe a declarao de "argv" como * um ponteiro para um ponteiro */ int main(int argc, char **argv[]) { int contador = 0; printf("Foram passados %d argumentos na linha de comando.\n",argc); while(*argv) { printf("%do argumento => %s\n",contador,*argv); contador++; argv++; } return(0); }

No que esquea que argv uma matriz de strings, ento os dados passados na linha de comando so todos considerados caracteres ASCII. Isto significa que os valores numricos devero ser convertidos. Para maiores detalhes sobre a converso de strings para valores numricos d uma olhada na seo Convertendo strings em nmeros.

17. Manipulando o ambiente 17.1 Exibindo as variveis de ambiente


Alm de argc e argv a funo main possui o parmetro env que lhe permite manipular as variveis de ambiente. env uma matriz de ponteiros para strings que armazena ponteiros para cada uma das variveis de ambiente. Abaixo segue um cdigo que exibe as variveis de ambiente do sistema:
/* exibindo as variveis de ambiente */ #include <stdio.h> int main(int argc,char *argv[],char *env[]) { int contador;

printf("Exibindo as variveis de ambiente\n"); printf("=================================\n"); for(contador = 0;env[contador] != NULL;contador++) printf("env[%d] => %s\n",contador,env[contador]); return(0); }

Voc pode tratar env como um ponteiro em vez de trat-lo como uma matriz de strings. Para isso voc deve declar-lo como um ponteiro para um ponteiro de strings. Exemplo;
/* tratando "env" como ponteiro */ #include <stdio.h> int main(int argc,char *argv[],char **env[]) { int contador = 0; printf("Exibindo as variveis de ambiente\n"); printf("=================================\n"); while(*env) printf("env[%d] => %s\n",contador++,*env++); return(0); }

17.2 Pesquisando uma varivel no ambiente


Para pesquisar um item no ambiente use a funo getenv() . Ela faz parte do arquivo de cabealho stdlib.h e sua sintaxe :
getenv("NOME")

Ela procura pela varivel NOME na lista de variveis de ambiente. Caso encontre ela retorna um ponteiro para a varivel, caso contrrio ela retorna NULL. Exemplo:
/* pesquisando uma varivel de ambiente */ #include <stdio.h> #include <stdlib.h> int main() { char *variavel; variavel = getenv("USER"); if(*variavel) printf("USER = %s\n",variavel); else printf("A varivel de ambiente USER no est definida.\n"); return(0); }

17.3 Alterando o valor ou adicionando uma varivel ao ambiente


Para alterar o valor ou adicionar uma varivel ao ambiente use a funo putenv() . Ela faz parte do arquivo de cabealho stdlib.h e sua sintaxe :
putenv("VARIAVEL=novo_valor")

Caso VARIAVEL exista no ambiente seu valor alterado para novo_valor , caso no exista esta adicionada ao ambiente. A funo retorna zero caso tudo ocorra bem, caso contrrio ela retorna -1. Exemplo:
/* adicionando uma varivel ao ambiente */ #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[],char *env[]) { int contador; char *variavel; if(putenv("GURU=samu")) printf("Erro ao adicionar a varivel de ambiente GURU\n"); else { variavel = getenv("GURU"); if(*variavel) printf("GURU = %s\n",variavel); else printf("A varivel de ambiente GURU no est definida.\n"); } return(0); }

18. Encerrando seu programa 18.1 return


O comando return(VALOR) encerra uma funo retornando VALOR para a funo chamadora. Caso a funo chamadora seja main() , o programa ser encerrado e o valor retornado passado para o sistema operacional. Exemplo:
/* verificando o funcionamento de "return" */ #include <stdio.h>

int soma(int a, int b) { int resultado; resultado = a + b; /* "resultado" ser passado a funo chamadora * no caso "printf" */ return(resultado); }

int main() { int nr1,nr2,valor; printf("Entre com o valor do primeiro nmero :"); scanf("%d",&nr1); printf("Entre com o valor do segundo nmero :"); scanf("%d",&nr2); /* Chamando a funo soma. O comando "return" * da funo soma retornar "resultado" para * aqui. */ printf("A soma dos dois %d\n",soma(nr1,nr2));

printf("Entre com o valor a ser retornado para o sistema operacional :"); scanf("%d",&valor); printf("Em ambiente Linux, digite o comando shell\n\n"); printf("$ echo $?\n\n"); printf("Para ver o valor retornado pelo programa\n"); /* "valor" ser retornado para o sistema operacional * pois este foi a funo chamadora de "main" */ return(valor); }

18.2 exit
Ao ser chamado, o comando exit(VALOR) encerra imediatamente o programa e retorna VALOR para o sistema operacional. Exemplo:
/* verificando o funcionamento de "exit" */ #include <stdio.h>

int soma(int a, int b) { int resultado; resultado = a + b; /* "exit" encerra o programa imediatamente e retorna * "resultado" para o sistema operacional */ exit(resultado); }

int main() { int nr1,nr2,valor; printf("Entre com o valor do primeiro nmero :"); scanf("%d",&nr1); printf("Entre com o valor do segundo nmero :"); scanf("%d",&nr2); /* Chamando a funo soma. O comando "return" * da funo soma retornar "resultado" para * aqui. */ printf("A soma dos dois %d\n",soma(nr1,nr2)); /* Nada abaixo disto ser executado pois o comando "exit" * chamado na funo "soma" acima encerrar imediatamente * o programa e retornar "resultado" para o sistema operacional */ printf("Entre com o valor a ser retornado para o sistema operacional :"); scanf("%d",&valor); printf("Em ambiente Linux, digite o comando shell\n\n"); printf("$ echo $?\n\n"); printf("Para ver o valor retornado pelo programa\n"); /* "valor" ser retornado para o sistema operacional * pois este foi a funo chamadora de "main" */ return(valor); }

18.3 abort
Ao encontrar a funo abort o programa imediatamente encerrado e um valor de erro padro do sistema retornado para o sistema operacional. Exemplo:

/* verificando o funcionamento de "abort" */ #include <stdio.h> #include <stdlib.h> int soma(int a, int b) { int resultado; resultado = a + b; /* Ao encontrar "abort" o programa imediatamente * encerrado sendo retornado para o sistema * operacional um dos valores de erro padro * do sistema */ abort(); exit(resultado); }

int main() { int nr1,nr2,valor; printf("Entre com o valor do primeiro nmero :"); scanf("%d",&nr1); printf("Entre com o valor do segundo nmero :"); scanf("%d",&nr2); /* Chamando a funo soma. O comando "return" * da funo soma retornar "resultado" para * aqui. */ printf("A soma dos dois %d\n",soma(nr1,nr2)); /* Nada abaixo disto ser executado pois o comando "exit" * chamado na funo "soma" acima encerrar imediatamente * o programa e retornar "resultado" para o sistema operacional */ printf("Entre com o valor a ser retornado para o sistema operacional :"); scanf("%d",&valor); printf("Em ambiente Linux, digite o comando shell\n\n"); printf("$ echo $?\n\n"); printf("Para ver o valor retornado pelo programa\n"); /* "valor" ser retornado para o sistema operacional * pois este foi a funo chamadora de "main" */ return(valor); }

18.4 Definindo funes a serem executadas no encerramento do programa


Para definir funes a serem executadas no encerramento do programa use a funo atexit() . Ela faz parte do arquivo de cabealho stdlib.h e sua sintaxe :
atexit(FUNO)

ela faz com que FUNO seja chamada quando o programa terminar normalmente, ou seja, com uma chamada a exit() ou com uma chamada a return() a partir de main() . FUNO no recebe argumentos, assim, caso ela precise acessar dados estes devem ter sido declarados como varivesi globais. Voc pode ainda definir mais de uma funo a ser chamada com atexit . Neste caso elas sero chamadas na ordem inversa da declarao, ou seja, a ltima funo declarada ser a primeira a ser chamada. Caso tudo ocorra bem atexit retorna zero, caso contrrio retorna -1. Observe abaixo um exemplo do uso de atexit :
/* utilizando "atexit" */ #include <stdio.h>

#include <stdlib.h> void primeira() { printf("Primeira funo chamada por atexit\n"); } void segunda() { printf("Segunda funo chamada por atexit\n"); } void terceira() { printf("Terceira funo chamada por atexit\n"); } int main() { printf("Chamando atexit\n\n"); atexit(primeira); atexit(segunda); atexit(terceira); return(0); }

Manipulando argumentos da linha de comando


Samuel Dias Neto - sdiasneto@yahoo.com.br Os argumentos da linha de comando so referenciados atravs dos parmetros argc e argv da funo main(). argc um inteiro que indica quantos argumentos foram passados para main(). Ele assume no mnimo o valor 1, pois o nome do programa considerado o primeiro argumento. argv um ponteiro para uma matriz de strings. Cada string desta matriz um argumento passado na linha de comando. argv[0] aponta para o nome do programa, argv[1] aponta para o primeiro argumento passado na linha de comando, argv[2] aponta para o segundo argumento, e assim por diante. Exemplo:
#include <stdio.h> int main(int argc, char *argv[]){ int c; printf("%d argumentos passados.\n",argc); for(c = 1;c < argc; c++){ printf("argumento %d => %s\n",c,argv[c]); } return 0;

Execuo:
nerd@nerd:~$ ./args arg1 arg2 arg3 4 argumentos passados. argumento 1 => arg1 argumento 2 => arg2 argumento 3 => arg3 nerd@nerd:~$

stdarg - listas de argumentos variveis


Samuel Dias Neto - sdiasneto@yahoo.com.br

Sintaxe:
#include <stdarg.h> void type void void va_start(va_list ap, last); va_arg(va_list ap, type); va_end(va_list ap); va_copy(va_list dest, va_list src);

Descrio: Uma funo pode ser chamada com um nmero varivel de argumentos sendo estes argumentos de diversos tipos. O arquivo de cabealho stdarg.h declara um tipo va_list e define trs macros para manipular uma lista de argumentos cuja quantidade e tipos so desconhecidos pela funo. A funo deve declarar um objeto do tipo va_list o qual usado pelas macros va_start, va_arg e va_end.
va_start

A macro va_start inicializa ap para uso posterior por va_arg e va_end e deve ser chamada primeiro. O parmetro last o nome do ltimo parmetro antes da lista de argumentos variveis, isto , o ltimo parmetro o qual a funo conhee o tipo. Porque o endereo deste parmetro pode ser usado na macro va_start, ele no deve ser declarado como uma varivel register, ou como uma funo ou como um array.
va_arg

A macro va_arg expande para uma expresso que tem o tipo e valor do prximo argumento na chamada. O parmetro ap aquele inicializado por va_start. Cada chamada a va_arg modifica ap de modo que a prxima chamada retorna o prximo argumento. O parmetro type um nome de tipo. Pode-se apontar para um objeto de um tipo especfico simplesmente adicionando um * ao tipo. O primeiro uso da macro va_arg aps a macro va_start retorna o argumento aps last. Chamadas sucessivas retornam os valores dos outros argumentos. Se no existe prximo argumento, ou se type no compatvel com o tipo do prximo argumento, erros aleatrios ocorrero. Se ap passado para uma funo que usa va_arg(ap,type) ento o valor de ap destrudo aps o retorno da funo.
va_end

Cada chamada de va_start deve ter uma chamada correspondente a va_end na mesma funo. Aps a chamada de va_end a varivel ap destruda. Vrias chamadas com va_start e va_end aninhadas so possveis. va_end pode ser uma macro ou uma funo.

Exemplo: A funo foo pega uma string de caracteres de formato e exibe o argumento associado com cada caracter de formato baseado no tipo.
#include <stdio.h>> #include <stdarg.h> void foo(char *fmt, ...) { va_list ap; int d; char c, *p, *s; va_start(ap, fmt); while (*fmt) switch(*fmt++) { case 's': /* string */ s = va_arg(ap, char *); printf("string %s\n", s); break; case 'd': /* int */ d = va_arg(ap, int); printf("int %d\n", d); break; case 'c': /* char */ /* need a cast here since va_arg only takes fully promoted types */ c = (char) va_arg(ap, int); printf("char %c\n", c); break; } va_end(ap); }

Usando o utilitrio make


Samuel Dias Neto - sdiasneto@yahoo.com.br

O que o utilitrio make Arquivos make padro O conceito de alvos Executando o Makefile Alvos frequentemente utilizados pela comunidade Dependncias Utilizando macros Utilizando regras de inferncia

O que o utilitrio make O utilitrio make uma poderosa ferramenta usada para compilar grandes projetos. Em vez de voc mesmo compilar e linkar todos os arquivos, o make pode fazer isto para voc com a vantagem de compilar somente o que for necessrio. Isto muito til no caso de pequenas modificaes em um grande projeto. Voc pode introduzir os comandos de compilao num arquivo make , assim no h necessidade de decorar as opes de comando que voc utilizou para compilar um projeto.

Veremos aqui a utilizao bsica do utilitrio make . Para aprofundar-se d uma olhada na page do GNU. Na seo de documentao voc encontrar um manual completo do make , s que em ingls.

Arquivos make padro Ao ser invocado, o comando make procura no diretrio atual por um dos trs arquivos abaixo na seguinte sequncia:
1. GNUmakefile 2. makefile 3. Makefile

Ao construir seu arquivo make recomendado o uso do nome Makefile porque:

A prpria documentao do GNU diz que deve-se evitar o uso do nome GNUmakefile pois este s deve ser empregado quando usamos os recursos suportados pelo comando make do GNU. Quando usamos os recursos do comando make UNIX padro devemos sempre usar o nome Makefile. Se, no futuro, voc quiser testar alguma modificao no Makefile sem mexer no original voc pode copilo com o nome de makefile , fazer as alteraes necessrias e executar pois makefile escolhido primeiro pelo comando make.

Alvos O comando make trabalha com o conceito de alvos. Nosso Makefile deve ter pelo menos um alvo. Crie um Makefile vazio e execute o comando make e voc ter uma sesso parecida com esta:
[nerd@aranha Makefile [nerd@aranha make: *** No [nerd@aranha teste]$ ls teste]$ make targets. Stop. teste]$

Observe que o comando foi encerrado dizendo que no haviam alvos. Agora vamos editar o Makefile e introduzir alvos:
# Estudando o comando make alvo1: @echo "Exibindo o alvo 1" alvo2: @echo "Exibindo o alvo 2" alvo3: @echo "Exibindo o alvo 3"

As linhas iniciadas com # so linhas de comentrios. Um nome de alvo deve sempre iniciar no comeo da linha e ser seguido por dois pontos.

Executando o Makefile

Para excutar o Makefile invocando um alvo basta entrar com o comando make seguido do nome do alvo na linha de comando. Observe:
[nerd@aranha teste]$ make alvo2 Exibindo o alvo 2 [nerd@aranha teste]$ make alvo3 Exibindo o alvo 3 [nerd@aranha teste]$ make Exibindo o alvo 1 [nerd@aranha teste]$

Veja que quando foi invocado sem alvo, o comando make assumiu o primeiro alvo do arquivo como o alvo padro. Voc pode tambm invocar vrios alvos no mesmo comando:
[nerd@aranha teste]$ make alvo2 alvo3 alvo1 Exibindo o alvo 2 Exibindo o alvo 3 Exibindo o alvo 1 [nerd@aranha teste]$

Alvos frequentemente utilizados pela comunidade Existem alguns nomes de alvo que so frequentemente utilizados por todos os programadores. Abaixo segue alguns deles:

all - utilizado como o primeiro nome de alvo do arquivo e, portanto, o nome de alvo padro. A utilizao deste alvo define o projeto inteiro. install -utilizado para instalar um projeto. clean - utilizado para remoo dos arquivo objeto e arquivos temporrios criados no processo de instalao. clobber - utilizado para remover os alvos que so construdos (normalmente executveis e bibliotecas). Voc remove estes alvos para reconstruir o projeto do zero. distclean - usado para remover tudo, exceto os arquivos originais que foram distribudos pela internet. Este alvo vai alm do clobber pois remove tambm os arquivos de configurao.

Dependncias O comando make tambm tem um conceito de dependncia. Quando um alvo A depende de um alvo B, o alvo B ser executado primeiro. Para o uso dos alvos frequentemente utilizados que esto descritos acima esteja ciente que:

install depende de all clobber depende de clean distclean depende de clobber

Vamos introduzir dependncias no nosso exemplo de estudo:


# Estudando o comando make alvo1: @echo "Exibindo o alvo 1" alvo2: alvo1 alvo3 @echo "Exibindo o alvo 2"

alvo3: alvo2 @echo "Exibindo o alvo 3"

Agora vamos executar o Makefile invocando alvo2 e ver como funcionam as dependncias:
[nerd@aranha teste]$ make alvo2 Exibindo o alvo 1 Exibindo o alvo 3 Exibindo o alvo 2 [nerd@aranha teste]$

Vemos que as dependncias devem vir aps o nome do alvo e devem estar separadas por um espao. A primeira dependncia tambm deve estar separada dos dois pontos por um espao.

Macros O arquivo make tambm pode utilizar-se de macros para aumentar sua funcionalidade. Observe como abaixo:
# Estudando o comando make # definindo uma macro ARQUIVO = teste.c #usando um nome de alvo frequentemente utilizado para #definir todo o projeto all: alvo1 alvo2 alvo3 alvo1: @echo "compilando "$(ARQUIVO) alvo2: @echo "linkando "$(ARQUIVO) alvo3: @echo "removendo "$(ARQUIVO)

Nesta implementao do nosso arquivo de estudo introduzimos um nome de alvo normalmente utilizado ( all ) para definir todo o projeto. Veja como seria a execuo deste Makefile:
[nerd@aranha teste]$ make compilando teste.c linkando teste.c removendo teste.c [nerd@aranha teste]$

Como mostrado no novo cdigo do nosso Makefile de estudo, onde quisermos que o nome da macro seja substitudo devemos colocar a expresso:
$(NOME_DA_MACRO)

Voc ainda pode alterar o valor da macro quando invocando o Makefile. Observe a sesso abaixo:
[nerd@aranha teste]$ make compilando teste.c linkando teste.c removendo teste.c [nerd@aranha teste]$ make ARQUIVO=main.c compilando main.c

linkando main.c removendo main.c [nerd@aranha teste]$

Veja que usamos o mesmo Makefile para processar outro arquivo atravs da definio de outro valor para a macro ARQUIVO na linha de comando.

Regras de inferncia As regras de inferncia so outro grande recurso do comando make . Para utiliz-las o make reconhece os seguintes tipos de arquivos dentre outros:

.c - arquivo fonte em linguagem C .h - arquivo de cabealho em linguagem C .cc - arquivo fonte em linguagem C++ .o - arquivo objeto compilado

Abaixo segue um exemplo da definio de uma regra de inferncia:


CC = gcc STD = _GNU_SOURCE .c.o: $(CC) -c -Wall $(CFLAGS) -D$(STD) $< -o $@

Vamos dissecar o trecho de cdigo acima:


1. As duas primeiras linhas
2. 3. CC = gcc STD = _GNU_SOURCE

utilizam macros para definir o compilador e o padro de compilao. Observe que estas macros sero substitudas na linha de ao do alvo .c.o montando, assim, o comando correto para a compilao do arquivo.

4. O alvo .c.o um tipo de alvo especial que define a regra de inferncia. Ele composto do sufixo do arquivo inicial ( .c ) seguido do sufixo do arquivo alvo ( .o ). Com esta declarao de alvo o comando make entende que se voc tem um alvo que um arquivo objeto ( .o ), existe um arquivo fonte ( .c ) de entrada e este mais recente, ele deve excutar os comandos que seguem. importante observar que numa definio de regra de inferncia no deve haver dependncia.

5. O comando para o alvo .c.o :


6. $(CC) -c -Wall $(CFLAGS) -D$(STD) $< -o $@

O comando deve iniciar com um caractere de tabulao. Para que o comando no seja exibido na sada padro preceda-o com o caracter @ . Veja que este comando usa amplamente macros. As macros CC e STD j foram vistas acima. A macro CFLAGS normalmente deixada em aberto para lhe dar flexibilidade. Ela pode ser usada para armazenar quaisquer outras opes de compilao no usadas constantemente, como a opo -g para

depurao. Isto feito pela passagem do valor correspondente a CFLAGS na prpria linha de comando quando invocando make , como foi mostrado acima na seo macros.

7. As macros $< e $@ so macros pr-definidas pelo comando make . Juntamente com $* , estas so as macros pr-definidas mais utilizadas e significam:
8. $* 9. 10. $@ 11. 12. $< 13. o arquivo alvo sem o sufixo o arquivo alvo o arquivo dependente. No caso do alvo ser um arquivo objeto( .o ), o dependente ser um arquivo fonte em linguagem C ( .c )

Para um melhor entendimento da utilizao de regras de inferncia vamos a um exemplo: Crie o arquivo fonte sam.c com o cdigo abaixo:
#include <stdio.h> int main() { printf("testando 1,2,3\n"); return(0); }

Agora crie o Makefile com o seguinte cdigo:


# Exemplo da utilizao de regras de inferncia CC = gcc .c.o: $(CC) -c $< -o $ $@ sam.o:

Observe que o Makefile tem o alvo sam.o . Utilizando as definies da regra de inferncia o make procura o arquivo sam.c . Se no encontrar, exibir uma mensagem de erro, provavelmente parecida com:
[nerd@aranha teste]$ make make: Nothing to be done for `sam.o'. [nerd@aranha teste]$

Caso encontre, o alvo ser criado:


[nerd@aranha teste]$ ls Makefile sam.c [nerd@aranha teste]$ make gcc -c sam.c -o sam.o [nerd@aranha teste]$ ls Makefile sam.c sam.o [nerd@aranha teste]$

Observe os valores substitudos para as macros $< e $@ . Aqui encerramos nossa pequena tour pelo comando make , lembrando que vimos apenas o "bsico do bsico" desta poderosa ferramenta.

Qualquer biz a mais no esquece de me enviar. E como dizia o meu querido professor de fsica Guido, l no CMR, toda vez que terminava a aula: " ..... estudem!" (a jogava o giz na canaleta do quadro negro e saia da sala).

Processando opes da linha de comando


Samuel Dias Neto - sdiasneto@yahoo.com.br

Para implementar o processamento da linha de comando em seus programas voc pode usar as funes getopt() e getopt_long().

getopt () A funo getopt() faz parte do arquivo de cabealho unistd.h e sua sintaxe :
#include <unistd.h> int getopt(int argc, char *argv[], char *opcoes) extern *optarg; extern optind; extern opterrr;

onde argc e argv so os conhecidos argumentos de main e opcoes uma string que armazena os caracteres de opo suportados pelo programa. A definio de opcoes deve ser algo como:
static char opcoes[] = "ab:c";

Observe que a letra b vem seguida de dois pontos. Isto indica que esta opo pode receber argumentos, o que no ocorre com as opes a e c. A funo getopt() ainda possui trs variveis externas que devem ser conhecidas pois sero utilizadas:

optarg uma varivel ponteiro que aponta para o argumento da opo, caso esta aceite. Assim, se getopt estiver processando uma opo do tipo -Wall ou -W all, a varivel optarg apontar para all. optind uma varivel inteiro que inicia com o valor 1. Ela usada por getopt para apontar para os argumentos passados na linha de comando. Como inicia com o valor 1, getopt processa a partir de argv[1]. No final do procesamento de getopt esta varivel estar apontando para o primeiro argumento do programa. Por exemplo, se sua linha de comando :
[nerd@aranha]$ cat -v teste

ao final do processamento desta linha, optind estar apontando para o argumento teste.

opterr uma varivel que exibe ou no mensagens de erro padro quando uma opo no definida na string opcoes passada. Ela inicializada com o valor 1 indicando TRUE. Quando ela tem este valor e um caractere no definido em opcoes passado, uma mensagem de erro padro exibida em

stderr,

que normalmente o monitor. Quando opterr configurada como 0 (zero) por seu programa, indicando FALSE, a mensagem de erro padro no exibida se um caractere no definido em opcoes for passado. Isto feito quando seu programa fornecer a mensagem de erro ou quando a mensagem deve ir para outro lugar em vez de stderr.

getopt

funciona da seguinte maneira:

A linha de comando analisada e a funo retorna um valor inteiro. Cada chamada da funo retorna um dos caracteres de opo passados. Ao retornar o caractere de opo, a varivel optarg aponta para o argumento da opo, caso este exista. Ao final da anlise, o valor -1 retornado pela funo. Neste ponto optind estar apontando para o primeiro argumento do programa. Por exemplo, digamos que a linha de comando a ser processada por getopt seja:
[nerd@aranha]$ gcc -Wall -g arquivo.c

a coisa funciona assim: 1. getopt chamada, analisa a linha de comando e retorna W. Como esta opo aceita argumentos e um argumento foi passado, optarg aponta para all. 2. getopt chamada novamente e agora retorna g. 3. o processamento das opes termina e getopt retorna -1. optind estar com o valor 3 indicando que o primeiro argumento do programa argv[3].

Para um melhor entendimento vamos a um exemplo usando getopt:


/* Processando opes da linha de comando com getopt() */ #include <stdio.h> #include <unistd.h> int main(int argc,char *argv[]) { int opcao; static char opcoes[] = "ab:c"; opterr = 0; while((opcao = getopt(argc,argv,opcoes)) != -1) switch(opcao) { case 'a': { printf("opo -a escolhida.\n"); break; } case 'b': { printf("opo -b escolhida.\n"); printf("esta opo recebeu o argumento %s.\n",optarg); break; } case 'c': { printf("opo -c escolhida.\n"); break; } default: printf("opo invlida!\n");

} for(;optind < argc;optind++) printf("argv[%d] = %s\n",optind,argv[optind]); return(0); }

Executando nosso programa de exemplo:


nerd@aranha:~/C$ ./opcoes -a opo -a escolhida. nerd@aranha:~/C$ ./opcoes -b teste opo -b escolhida. esta opo recebeu o argumento teste. nerd@aranha:~/C$ ./opcoes -c opo -c escolhida. nerd@aranha:~/C$ ./opcoes -d opo invlida!

getopt_long() Com getopt_long voc pode processar opes longas tipo -- version. Esta funo faz parte do arquivo de cabealho getopt.h e sua sintaxe :
#include <getopt.h> int getopt_long(int argc, char *argv[], char *opcoes, option *opcoes_longas, int *indice_opcoes_longas)

onde argc, argv e opcoes j so conhecidos. opcoes uma string do tipo daquela mostrada no uso de getopt() acima. O argumento opcoes_longas um ponteiro para uma matriz de estruturas do tipo option. Esta estrutura pr-definida em getopt.h e sua composio :
struct option { const char *name;/* int has_arg; /* int *flag; /* int val; /* }

Nome da opo longa */ Diferente de zero se opo aceita argumento */ NULL(zero) ou um ponteiro para um valor int */ Valor de retorno */

Abaixo segue um exemplo de como deve ser a declarao da matriz de estruturas do tipo option a ser usada com getopt_long:
static struct option opcoes_longas[]= { {"help",0,0,'h'}, /* name,has_arg,flag,val */ {"version",0,0,'v'}, /* name,has_arg,flag,val */ {0,0,0,0} };

O ltimo elemento da matriz deve ter valor zero em todos os componentes da estrutura option.

e val trabalham em conjunto. Quando voc quiser que getopt_long retorne uma letra que abrevia a opo longa, use como mostrado acima, ou seja, flag com o valor de zero e val com a letra a ser retornada.
flag

Quando quiser usar flag voc deve fazer assim:


static int chave = 0; /* iniciando a flag */ static struct option opcoes_longas[]= { {"help",0,0,'h'}, {"version",0,&chave,1}, {0,0,0,0} };

Neste caso, se a opo passada na linha de comando for "help" a funo getopt_long retornar "h", simulando assim a passagem de uma opo curta, porm se a opo passada for "version", o valor 1 ser armazenado na varivel "chave" O argumento indice_opcoes_longas usado da seguinte maneira: um ndice interno da funo getopt_long inicia em zero e usado para comparar a opo passada na linha de comando com o elemento opcoes_longas[ndice].name. Se a opo passada for igual a opcoes_longas[ndice].name, o ndice armazenado em indice_opcoes_longas para ser usado no processamento dos outros elementos da estrutura. Caso contrrio o ndice incrementado e nova comparao feita at o final da matriz de estruturas. Vamos a um exemplo:
/* Processando opes da linha de comando com getopt_long() */ #include <stdio.h> #include <getopt.h> int main(int argc,char *argv[]) { int opcao; static int chave = 0; int indice_opcoes_longas = 0; static char opcoes[] = "hg:c"; static struct option opcoes_longas[]= { {"help",0,0,'h'}, {"version",0,&chave,1}, {0,0,0,0} }; opterr = 0; while((opcao = getopt_long(argc,argv, opcoes, opcoes_longas, &indice_opcoes_longas)) != -1) switch(opcao) { case 0: break; case 'h': { printf("Exibindo ajuda.\n"); break; } case 'g': { printf("opo -g escolhida.\n"); printf("esta opo recebeu o argumento %s.\n",optarg); break;

} case 'c': { printf("opo -c escolhida.\n"); break; } default: printf("opo invlida!\n"); } if(chave != 0) printf("Verso 1.0\n"); return(0); }

Executando o programa:
nerd@aranha:~/C$ ./opcoes_longas -h Exibindo ajuda. nerd@aranha:~/C$ ./opcoes_longas -g teste opo -g escolhida. esta opo recebeu o argumento teste. nerd@aranha:~/C$ ./opcoes_longas -c opo -c escolhida. nerd@aranha:~/C$ ./opcoes_longas --version Verso 1.0 nerd@aranha:~/C$ ./opcoes_longas -b opo invlida! nerd@aranha:~/C$ ./opcoes_longas --debug opo invlida!

Tratamento de erro
Samuel Dias Neto - sdiasneto@yahoo.com.br

Toda a programao em linguagem C baseada em funes (at mesmo main() uma funo). O valor de retorno de uma funo indica se esta foi executada com sucesso ou no. Por conveno, funes que retornam um valor inteiro indicam erro quando retornam -1. Qualquer outro valor retornado indica sucesso. Normalmente se usa o valor zero ou valores positivos para indicar o sucesso. Se a funo retorna um ponteiro, a falha indicada pelo retorno de um ponteiro NULL. Qualquer ponteiro no nulo indica sucesso. Como as funes que retornam valores inteiros normalmente usam o valor -1 para indicar que houve alguma falha, voc pode usar o seguinte cdigo para identificar se ocorreu algum erro numa chamada a uma funo que retorna um valor inteiro:
if((VARIVEL = FUNO) < 0) /* um erro ocorreu */ { COMANDOS PARA TRATAMENTO DO ERRO }

Se a funo retorna um ponteiro, normalmente o erro indicado por um ponteiro nulo e voc pode usar o cdigo:
if((VARIVEL = FUNO) == 0) /* um erro ocorreu */ { COMANDOS PARA TRATAMENTO DO ERRO }

Antigamente, quando uma funo falhava, o erro era indicado atravs de uma varivel externa especial chamada errno. A funo retornava -1 (no caso de valores inteiros), ou NULL (no caso de ponteiros) e armazenava o cdigo do tipo de erro em errno. Exemplo:
#include <stdio.h> #include <stdlib.h> int main() { extern int errno; FILE *arquivo; if((arquivo = fopen("arquivoX","r")) == NULL) { printf("errno = %d\n",errno); /* exibindo o cdigo de erro */ exit(errno); } return(0); }

O programa acima compilado e executado deve gerar uma sada assim:


$ ./erro1 errno = 2 $ echo $? 2

Observe que o arquivo "arquivoX" no deve existir para este exemplo funcionar.

Atualmente voc no precisa declarar errno como uma varivel externa, basta incluir o arquivo de cabealho errno.h e voc j pode usar errno. Alm disso foram definidas vrias macros que referenciam os erros codificados por errno. Abaixo podemos ver uma lista com algumas delas:
MACRO
E2BIG EACCESS EFBIG EINVAL EIO

DESCRIO DO ERRO Lista de argumentos muito longa Permisso negada Arquivo muito grande Argumento invlido Erro de entrada/sada

ENOENT

Arquivo ou diretrio inexistente

Para ver a lista completa d uma olhada na manpage do errno:


man errno

A utilizao destas macros permite que voc personalize sua mensagem de erro. Por exemplo:
#include <stdio.h> #include <stdlib.h> #include <errno.h> /* usando macros para personalizar suas mensagens de erro */ int main(int argc, char *argv[]){ FILE *arquivo; if((arquivo = fopen(argv[1],"r")) == NULL){ if(errno == ENOENT){ printf("Erro: O arquivo %s no existe.\n",argv[1]); exit(errno); } } fclose(arquivo); return(0); }

Rodando o exemplo:
$ ./erro2 arquivoX Erro: O arquivo arquivoX no existe. $ echo $? 84

Observe que "arquivoX" no existe e o programa emite a mensagem de erro personalizada. Observe tambm que o valor de errno diferente do primeiro exemplo. Esta a nova definio de errno.

Voc tambm pode usar a funo strerror() para exibir uma mensagem ao usurio indicando o erro, porm normalmente estas mensagens retornam em ingls. Esta funo faz parte do arquivo de cabealho string.h. Veja um exemplo do uso de strerror():
#include #include #include #include <stdio.h> <stdlib.h> <errno.h> <string.h>

/* usando strerror() */ int main(int argc, char *argv[]){ FILE *arquivo; if((arquivo = fopen(argv[1],"r")) == NULL){ printf("%s.\n",strerror(errno)); exit(errno); } fclose(arquivo);

return(0); }

Execuo:
$ ./errno3 arquivoX No such file or directory.

importante lembrar que a string retornada por strerror() s vlida at que esta funo seja chamada novamente.

Entrada de strings
Samuel Dias Neto - sdiasneto@yahoo.com.br

Para capturar a entrada de cadeias de caracteres em C podemos usar a funo scanf() com o especificador de formato %s. Exemplo:
/* scanf0.c */ #include <stdio.h> int main(){ char nome[21]; printf("Entre com seu nome :"); scanf("%s",nome); printf("Nome: %s.\n",nome); return(0); }

Execuo:
$ ./scanf0 Entre com seu nome :Samuel Nome: Samuel.

Agora, digamos que o usurio resolve digitar o nome completo:


$ ./scanf0 Entre com seu nome :Samuel Dias Neto Nome: Samuel.

..... parece que no funcionou corretamente. Mas tem um biz. Para que scanf() leia tudo que for digitado at encontrar um caracter de nova linha faa assim:
/* scanf1.c */ #include <stdio.h> int main(){ char nome[21]; printf("Entre com seu nome :");

scanf("%[^\n]",nome); printf("Nome: %s.\n",nome); return(0); }

Execuo:
./scanf1 Entre com seu nome :Samuel Dias Neto Nome: Samuel Dias Neto.

Agora funcionou legal. A especificao "%[^\n]" diz para aceitar a entrada at que o caracter \n (nova linha) seja encontrado.

E, se o usurio desligado digitar uns espaos antes do nome:


$ ./scanf1 Entre com seu nome : Samuel Dias Neto Nome: Samuel Dias Neto.

Basta inserir um espao antes do caracter % no especificador:


/* scanf2.c */ #include <stdio.h> int main(){ char nome[21]; printf("Entre com seu nome :"); scanf(" %[^\n]",nome); printf("Nome: %s.\n",nome); return(0); }

Execuo:
$ ./scanf2 Entre com seu nome : Nome: Samuel Dias Neto. Samuel Dias Neto

Agora ficou melhor, n ???

E se o nome do cara for muito grande ???


$ ./scanf2 Entre com seu nome :Um Dois Trs de Oliveira Quatro Raimundo da Silva Nome: Um Dois Trs de Oliveira Quatro Raimundo da Silva. Falha de segmentao

Ops ..... falha de segmentao. Houve problema. Mais um biz: para limitar a quantidade de caracteres da entrada basta colocar o nmero aps o caracter % no especificador:

/* scanf3.c */ #include <stdio.h> int main(){ char nome[21]; printf("Entre com seu nome :"); scanf(" %20[^\n]",nome); printf("Nome: %s.\n",nome); return(0); }

Execuo:
$ ./scanf3 Entre com seu nome :Um Dois Trs de Oliveira Quatro Raimundo da Silva Nome: Um Dois Trs de Oliv.

Agora no houve falha de segmentao.

Observe que ao declarar a varivel para armazenar o nome ( char nome[21]) sempre colocamos um caracter a mais para armazenar o caracter nulo que encerra uma string. Observe tambm que no precisamos do operador "endereo de" ( & ) ao indicar a varivel nome na funo scanf() ( scanf(" %20[^\n]",nome) ), pois em C as strings so consideradas arrays de caracteres. E ao passar um array na verdade estamos passando o endereo do primeiro elemento do array.

Вам также может понравиться