Sei sulla pagina 1di 60

UNIVERSIDADE REGIONAL INTEGRADA E DAS M ISSES CAMPUS ERECHIM

DEPARTAMENTO
DE

DO

ALTO URUGUAI

ENGENHARIAS E CINCIA DA COMPUTAO

CURSO DE CINCIA DA COMPUTAO

Linguagem de Programao II
Linguagem C

Prof. Neilor Tonin nat@uri.com.br http://www.inf.uri.com.br/neilor

1 Semestre/2004

Apostila de Linguagem de Programao II

Sumrio
1.COMPILADOR.......................................................................................................................... 5 1.1 AMBIENTE DE COMPILAO......................................................................................................... 5 2. ESTRUTURA DE UM PROGRAMA EM C......................................................................... 6 2.1 BLOCO DE DIRETIVAS DE COMPILAO:......................................................................................... 6 2.2 BLOCO DE DECLARAES:........................................................................................................... 6 2.3 BLOCO DE IMPLEMENTAO:........................................................................................................ 6 3. DADOS....................................................................................................................................... 7 3.1 ELEMENTOS DA LINGUAGEM......................................................................................................... 7 3.1.1 Letras (alfanumricas) - PASCAL e C:............................................................................. 7 3.1.2 Dgitos (numricos) - PASCAL e C:.................................................................................. 7 3.1.3 Smbolos Especiais.............................................................................................................7 3.1.4 Palavras Reservadas ou Palavras Chave.......................................................................... 7 3.1.5 Delimitadores.....................................................................................................................8 3.2 ELEMENTOS DEFINIDOS PELO USURIO............................................................................................ 8 3.2.1 Identificadores................................................................................................................... 8 3.2.2 Comentrios....................................................................................................................... 8 3.2.3 Endentao........................................................................................................................ 8 3.3 TIPOS DE DADOS........................................................................................................................ 8 3.3.1 Tipos predefinidos pela linguagem....................................................................................8 3.4 CONVERSES DE TIPOS DE DADOS.................................................................................................. 9 3.5CONSTANTES E VARIVEIS............................................................................................................ 9 3.5.1Constantes........................................................................................................................... 9
3.5.1.1Constantes dos tipos bsicos......................................................................................................9 3.5.1.2 Constantes de barra invertida................................................................................................... 9

3.5.2Nomes de Variveis...........................................................................................................10 3.5.3 Declarao e Inicializao de Variveis......................................................................... 10 3.6 OPERADORES ARITMTICOS........................................................................................................ 11 3.7 OPERADORES DE ATRIBUIO...................................................................................................... 12 3.8 OPERADORES RELACIONAIS E LGICOS........................................................................................... 12 3.9 OPERADORES BIT A BIT.............................................................................................................. 13 3.10 OPERADORES DE INCREMENTO E DECREMENTO.............................................................................. 13 3.11 OPERADOR CONDICIONAL........................................................................................................ 14 3.12 OPERADOR VRGULA............................................................................................................... 14 3.13 TABELA DE PRECEDNCIAS DOS OPERADORES............................................................................... 14 4. COMANDOS DE E/S..............................................................................................................15 4.1 A FUNO PRINTF()............................................................................................................... 15 4.2 A FUNO SCANF()............................................................................................................... 16 4.3 AS FUNES GETCHE() E GETCH()......................................................................................... 17 4.4 COMANDOS DE DESVIO INCONDICIONAL........................................................................................ 17 4.5 ESTRUTURAS DE CONTROLE....................................................................................................... 18 4.5.1 Seqncia......................................................................................................................... 18 4.5.2 Comandos condicionais................................................................................................... 18
4.5.2.1 IF............................................................................................................................................ 18 4.5.2.2 Comando de Seleo mltipla: SWITCH ou CASE .............................................................19

4.5.3 Comandos de Repetio...................................................................................................20


4.5.3.1 For.......................................................................................................................................... 20 4.5.3.2 While...................................................................................................................................... 21

Apostila de Linguagem de Programao II

4.5.3.3 Do While ou Repeat ...............................................................................................................22

4.5.4 Comandos de desvio.........................................................................................................22


4.5.4.1 Comando break.......................................................................................................................22 4.5.4.2 Comando continue.................................................................................................................. 22 4.5.4.3 Funo Exit............................................................................................................................ 23 4.5.4.4 Comando return...................................................................................................................... 23

5. FUNES E PROCEDIMENTOS........................................................................................24 5.1 FUNES................................................................................................................................ 24 5.2 ESTILOS E PROTTIPOS DAS FUNES............................................................................................ 24 5.2.1 Argumentos das funes.................................................................................................. 24
5.2.1.1 Passagem de parmetros por valor......................................................................................... 24 5.2.1.2 Passagem de parmetros por referncia..................................................................................25

5.2.2 Tipos de funes...............................................................................................................25 5.3 ARGUMENTOS PASSADOS A PROGRAMAS......................................................................................... 27 6. VETORES, MATRIZES E STRINGS...................................................................................28 6.1 VETORES................................................................................................................................ 28 6.2 STRINGS (OU CADEIAS DE CARACTERES)...................................................................................... 29 6.2.1 gets:..................................................................................................................................29 6.2.2 strcat:............................................................................................................................... 29 6.2.3 strcpy:...............................................................................................................................30 6.2.4 strlen:............................................................................................................................... 30 6.2.5 Strcmp.............................................................................................................................. 30 6.3 MATRIZES............................................................................................................................... 32 6.3.1 Matrizes bidimensionais.................................................................................................. 32 6.3.2 Matrizes de strings........................................................................................................... 32 6.3.3 Matrizes multidimensionais............................................................................................. 32 6.3.4 Matrizes e vetores como parmetros de funes............................................................. 33 7.PONTEIROS............................................................................................................................. 35 7.1 PONTEIROS PARA MATRIZES........................................................................................................ 7.2 PONTEIROS PARA PONTEIROS....................................................................................................... 7.3 ARITMTICA COM PONTEIROS...................................................................................................... 7.4 PONTEIROS PARA FUNES.......................................................................................................... 36 37 38 38

8. ESTRUTURAS, UNIES E ITENS DIVERSOS................................................................. 40 8.1 ESTRUTURAS........................................................................................................................... 40 8.2 PASSANDO UMA ESTRUTURA PARA UMA FUNO.............................................................................. 40 8.2.1 Matriz de Estruturas........................................................................................................ 41 8.2.2 Estruturas dentro de estruturas....................................................................................... 41 8.2.3 Ponteiros para estruturas................................................................................................ 42 9. ARQUIVOS..............................................................................................................................44 9.1 DECLARAO DE ARQUIVOS........................................................................................................ 45 9.2 FUNES DE ABERTURA E FECHAMENTO DE ARQUIVOS...................................................................... 45 9.3 FUNES DE ESCRITA E GRAVAO PARA ARQUIVO BINRIO............................................................... 46 9.4 FUNES DE ESCRITA E GRAVAO EM ARQUIVOS TEXTO............................................................... 47 9.4.1 Funes "fseek" , "ftell" e "rewind".................................................................................49 9.5 RESUMO DE UTILIZAO DE ARQUIVOS.......................................................................................... 50 10. ALOCAO DINMICA DE MEMRIA....................................................................... 54 10.1 LISTA ENCADEADA COM ALOCAO DINMICA DE MEMRIA:............................................................ 56

Apostila de Linguagem de Programao II

1.COMPILADOR
O Compilador utilizado para este curso (disciplina) ser o Turbo C++ 3.0 para DOS por vrios motivos: exige poucos recursos de hardware, tem todas as funes necessrias, fcil de copiar e instalar entre outros.

1.1 Ambiente de Compilao


O ambiente de compilao apresentado abaixo. Dois arquivos esto abertos no momento: arqprova.cpp e exem-arq.cpp. Para compilar o fonte, basta pressionar CRTL + F9. A janela inferior Watch, serve para visualisar (Watch: ver, assistir) variveis em tempo de execuo. fundamental configurar corretamente o compilador para que o mesmo funcione perfeitamente. O primeiro passo verificar se os diretrios esto configurados corretamente: Options... Directories... (e a colocar os diretrios onde esto os include e as bibliotecas).

Tambm muito importante saber depurar o programa para saber exatamente o que est ocorrendo no momento de execuo ( valores de variveis). Para tanto basta utilizar os seguintes atalhos: CRTL + F7: digite a varivel que voc deseja saber o valor em tempo de execuo (essa varivel ser apresentada na janela Watch. Podem ser adicionadas tantas variveis quantas forem necessrias. F7: com F7, o programa ir executando passo-a-passo, linha a linha, para que seja possvel entender a alterao dos valores das variveis inspecionadas.

importante incluir a biblioteca grfica no caso de compilar algum programa em modo grfico, com imagens: Options... Linker... Libraries

Mais opes sero vistas no decorrer da disciplina. Por ora o apresentado aqui suficiente.

Apostila de Linguagem de Programao II

2. ESTRUTURA DE UM PROGRAMA EM C
Normalmente um programa em C possui trs partes distintas: Bloco de Diretivas de Compilao, Bloco de declaraes e Bloco de Implementao . Vejamos um primeiro programa em C:
/* Um Primeiro Programa */

#include <stdio.h> void main (void){ printf ("Ola! Eu estou vivo!"); }

2.1 Bloco de Diretivas de Compilao:


Como a linguagem C no possui nenhum comando de entrada e sada incorporado linguagem, todas essas operaes so realizadas atravs de funes que encontram-se nas bibliotecas da linguagem. Para utilizar essas funes dentro do programa necessrio incluir o cabealho das funes no incio do programa atravs da diretiva de compilao #include:
#include <stdio.h> /* bibl. padro de comandos de entrada/sada encontrados no diretrio padro*/ #include outros.h /*inclui a bliblioteca criada pelo usurio que se encontra no diretrio corrente */

Tambm nesse bloco podemos definir as macros para o nosso programa. Uma macro pode ser simplesmente a substituio de um texto como a implementao de uma pequena funo, por exemplo:
#define MAXINT 32767 #define triplo(x) ((x)*3) #define pqt Pressione Qualquer Tecla Para Continuar...

2.2 Bloco de Declaraes:


No bloco das declaraes so declaradas todas as variveis globais, tipos definidos pelo usurio, estruturas, unies e declaradas todas as funes (exceto a main) que esto implementadas no programa, atravs de um prottipo (cabealho) da mesma.
int soma(int x, int y); int num, quant; char nome[50];

2.3 Bloco de Implementao:


No bloco de implementaes so implementadas todas as funes que compem o programa. Inicialmente se implementa a funo principal, que a primeira a ser executada e logo abaixo todas as demais funes. Abaixo apresentado um programa bsico com uma funo mensagem() alm da funo main(void).
#include <stdio.h> void mensagem (void); //prottipo da funo mensagem void main (void){ // funo principal mensagem(); printf ("Eu estou vivo!\n"); } void mensagem (void){ //funo mensagem printf ("Ola! "); }

Apostila de Linguagem de Programao II

3. DADOS
Nessa sesso sero apresentados as variveis e operaes utilizadas na linguagem C.

3.1 Elementos da Linguagem


Normalmente uma linguagem de programao possui dois tipos de elementos: os elementos definidos pela linguagem e os elementos definidos pelo prprio usurio:

3.1.1 Letras (alfanumricas) - PASCAL e C:


A at Z a at z

3.1.2 Dgitos (numricos) - PASCAL e C:


0 at 9

3.1.3 Smbolos Especiais


Todas as linguagens possuem smbolos especiais que so diferentes em cada linguagem, mas que tem a mesma finalidade:
Operador + * / = = > < >= <= != = ( ) /* */ ; " ou ' Significado adio subtrao multiplicao diviso comp. igualdade maior que menor que maior ou igual menor ou igual diferente atribuio parnteses incio de comentrio final de comentrio separador demarca strings ou caracteres

3.1.4 Palavras Reservadas ou Palavras Chave


Palavras Reservadas so smbolos que possuem significado definido na linguagem, no podendo ser redefinidos ou usado como nome de identificador.
auto default float register struct volatile break do for return switch while case double goto short typedef char else if signed union const enum int sizeof unsigned continue extern long static void

Na linguagem C, o restante dos comandos so todos funes (da biblioteca padro ou no). Todas as palavras reservadas devem ser escritas em minsculo.

Apostila de Linguagem de Programao II

3.1.5 Delimitadores
Os elementos da linguagem (identificadores, nmeros e smbolos especiais) devem ser separados por pelo menos um dos seguintes delimitadores: branco, final de linha ou comentrio.

3.2 Elementos definidos pelo Usurio


3.2.1 Identificadores
Um identificador um smbolo definido pelo usurio que pode ser um rtulo (label), uma constante, um tipo, uma varivel, um nome de programa ou subprograma (procedimento ou funo). Os identificadores normalmente devem comear com um caractere alfabtico e no pode conter espaos em branco. No C somente os 32 primeiros caracteres so significativos.

3.2.2 Comentrios
Os comentrios no tem funo nenhuma para o compilador e serve apenas para aumentar a legibilidade e clareza do programa.

3.2.3 Endentao
A endentao tambm no tem nenhuma funo para o compilador e serve para tornar a listagem do programa mais clara dando hierarquia e estrutura ao programa.

3.3 Tipos de Dados


Um Tipo de Dado define o conjunto de valores que uma varivel pode assumir e as operaes que podem ser feitas sobre ela.Toda varivel em um programa deve ser associada a um e somente um tipo de dado. Esta associao feita quando a varivel declarada na parte de declarao de variveis do programa.

3.3.1 Tipos predefinidos pela linguagem


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 8 8 8 16 16 16 16 16 16 32 32 32 32 64 80 Num de bits 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 Intervalo 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.

Apostila de Linguagem de Programao II

3.4 Converses de tipos de dados


Ao contrrio das outras linguagens, C e C++ executam converses automticas de dados para um tipo maior ou trunca o valor para um tipo menor. Devemos ter cuidado quando usamos operaes de modo misto em C ou C++, pois os valores podem ser truncados, enquanto que no Pascal devemos prever exatamente o tipo da varivel que necessitamos, por exemplo:
Exemplo 1
int a, b; float c; a=5; b=3; c=a/b; c=1,000000

Exemplo 2
float a, b; int c; a=5; b=3; c=a/b; c=1

Exemplo 3
int a; float b,c; a=5; b=3; c=a/b; c=1,666667

A linguagem C e C++ permitem a converso temporria dos tipos de variveis atravs do operador de converso. Sempre que voc necessitar a mudar o formato de uma varivel temporariamente, simplesmente preceda o identificador da varivel com o tipo entre parnteses para aquele que quiser converter. Se utilizarmos o primeiro exemplo de C acima podemos obter o resultado esperado usando um operador de converso ou cast:
int a, b; float c; a=5; b=3; c=(float)a/b; c=1,666667

3.5Constantes e Variveis
3.5.1Constantes
Constantes so valores que so mantidos fixos pelo compilador. J usamos constantes neste curso. So consideradas constantes, por exemplo, os nmeros e caracteres como 45.65 ou 'n', etc...

3.5.1.1Constantes dos tipos bsicos


Abaixo vemos as constantes relativas aos tipos bsicos do C:
Tipo de Dado char int long int short int unsigned int float double Exemplos de Constantes 'b' '\n' '\0' 2 32000 -130 100000 -467 100 -30 50000 35678 0.0 23.7 -12.3e-10 12546354334.0 -0.0000034236556

Constantes em Octal sempre devem iniciar com 0, como em mem = 01777 Constantes em Hexa sempre devem iniciar com 0x ou 0X, como em mem = 0x1FA

Apostila de Linguagem de Programao II

3.5.1.2 Constantes de barra invertida


O C utiliza, para nos facilitar a tarefa de programar, vrios cdigos chamados cdigos de barra invertida. Estes so caracteres que podem ser usados como qualquer outro. A lista completa dos cdigos de barra invertida dada a seguir:
Cdigo \b \f \n \r \t \" \' \0 \\ \v \a \N \xN Significado Retrocesso ("back") Alimentao de formulrio ("form feed") Nova linha ("new line") Retorno de carro ("carriage return") Tabulao horizontal ("tab") Aspas Apstrofo Nulo (0 em decimal) Barra invertida Tabulao vertical Sinal sonoro ("beep") Constante octal (N o valor da constante) Constante hexadecimal (N o valor da constante)

3.5.2Nomes de Variveis
O C "Case Sensitive" (sensvel caixa), isto , maisculas e minsculas fazem diferena. Ao se declarar uma varivel com o nome soma ela ser diferente de Soma, SOMA, SoMa ou sOmA. Da mesma maneira, os comandos if e for, por exemplo, s podem ser escritos em minsculas pois seno o compilador no ir interpret-los como sendo variveis. As variveis no C podem ter qualquer nome se duas condies forem satisfeitas: o nome deve comear com uma letra ou sublinhado (_) e os caracteres subsequentes devem ser letras, nmeros ou sublinhado (_). H apenas mais duas restries: o nome de uma varivel no pode ser igual a uma palavra reservada, nem igual ao nome de uma funo declarada pelo programador, ou pelas bibliotecas do C. Variveis de at 32 caracteres so aceitas. Mais uma coisa: bom sempre lembrar que o C "case sensitive" e portanto devese prestar ateno s maisculas e minsculas. Quanto aos nomes de variveis... uma prtica tradicional do C, usar letras minsculas para nomes de variveis e maisculas para nomes de constantes. Isto facilita na hora da leitura do cdigo; Quando se escreve cdigo usando nomes de variveis em portugus, evita-se possveis conflitos com nomes de rotinas encontrados nas diversas bibliotecas, que so em sua maioria absoluta, palavras em ingls.

3.5.3 Declarao e Inicializao de Variveis


As variveis no C devem ser declaradas antes de serem usadas. A forma geral da declarao de variveis :
tipo_da_varivel lista_de_variveis;

As variveis da lista de variveis tero todas o mesmo tipo e devero ser separadas por vrgula. Como o tipo default do C o int, quando vamos declarar variveis int com algum dos modificadores de tipo, basta colocar o nome do modificador de tipo. Assim um long basta para declarar um long int. Por exemplo, as declaraes
char ch, letra; long count; float pi;

Apostila de Linguagem de Programao II

10

declaram duas variveis do tipo char (ch e letra), uma variavel long int (count) e um float pi. H trs lugares nos quais podemos declarar variveis: O primeiro fora de todas as funes do programa. Estas variveis so chamadas variveis globais e podem ser usadas a partir de qualquer lugar no programa. Pode-se dizer que, como elas esto fora de todas as funes, todas as funes as vem. O segundo lugar no qual se pode declarar variveis no incio de um bloco de cdigo. Estas variveis so chamadas locais e s tm validade dentro do bloco no qual so declaradas, isto , s a funo qual ela pertence sabe da existncia desta varivel, dentro do bloco no qual foram declaradas. O terceiro lugar onde se pode declarar variveis na lista de parmetros de uma funo. Mais uma vez, apesar de estas variveis receberem valores externos, estas variveis so conhecidas apenas pela funo onde so declaradas. Veja o programa abaixo:
#include <stdio.h> int contador; int func1(int j) { ... } void main(void){ char condicao; int i; for (i=0; ...) { float f2; ... func1(i); } ... }

/* Bloco do for */

A varivel contador e uma varivel global, e acessvel de qualquer parte do programa. As variveis condio e i, s existem dentro de main(void), isto so variveis locais de main. A varivel float f2 um exemplo de uma varivel de bloco, isto , ela somente conhecida dentro do bloco do for, pertencente funo main. A varivel inteira j um exemplo de declarao na lista de parmetros de uma funo (a funo func1). As regras que regem onde uma varivel vlida chamam-se regras de escopo da varivel. H mais dois detalhes que devem ser ressaltados. Duas variveis globais no podem ter o mesmo nome. O mesmo vale para duas variveis locais de uma mesma funo. J duas variveis locais, de funes diferentes, podem ter o mesmo nome sem perigo algum de conflito. Podemos inicializar variveis no momento de sua declarao. Para fazer isto podemos usar a forma geral tipo_da_varivel nome_da_varivel = constante; Isto importante pois quando o C cria uma varivel ele no a inicializa. Isto significa que at que um primeiro valor seja atribudo nova varivel ela tem um valor indefinido e que no pode ser utilizado para nada. Nunca presuma que uma varivel declarada vale zero ou qualquer outro valor. Exemplos de inicializao so dados abaixo:
char ch='D'; int count=0; float pi=3.141;

Apostila de Linguagem de Programao II

11

3.6 Operadores Aritmticos


Operador
+ * / % ++ --

Ao
Soma (inteira e ponto flutuante) Subtrao ou Troca de sinal (inteira e ponto flutuante) Multiplicao (inteira e ponto flutuante) Diviso (inteira e ponto flutuante) Resto de diviso (de inteiros) Incremento (inteiro e ponto flutuante) Decremento (inteiro e ponto flutuante)

3.7 Operadores de atribuio


Em C e C++ temos os seguintes operadores de atribuio:
=
Ex: i=2; i+=4; x *= y+1; p %= 5;

+=
> > > >

*=

/=

%=

atribui o nmero 2 varivel i i=i+4; x=x*(y+1); p = p % 5;

O C admite as seguintes equivalncias, que podem ser usadas para simplificar expresses ou para facilitar o entendimento de um programa: Expresso Original
x=x+k; x=x-k; x=x*k; x=x/k; x=x>>k; x=x<<k; x=x&k; etc...

Expresso Equivalente
x+=k; x-=k; x*=k; x/=k; x>>=k; x<<=k; x&=k;

3.8 Operadores relacionais e lgicos


Os operadores relacionais so operadores binrios que devolvem os valores lgicos verdadeiro e falso.
Operador > < >= <= == != Ao maior que menor que maior ou igual menor ou igual igual diferente

Apostila de Linguagem de Programao II

12

Os operadores lgicos so usados para combinar expresses relacionais. Tambm devolvem como resultado valores lgicos verdadeiro ou falso. Operador && || ! ^ Ao e ou no ou exclusivo

Uma expresso relacional ou lgica em C ou C++, retornar zero para o valor lgico falso e um para o valor lgico verdade. No entanto, qualquer valor diferente de zero ser considerado um valor verdade quando inserido em uma expresso lgica.

3.9 Operadores bit a bit


Em C e C++ temos os operadores bit a bit. So operadores capazes de alterar os valores dos bits de uma varivel. Funcionam apenas com os tipos char e int. Operador & | ~ ^ >> << Exemplos:
char a, b, c; a=1; b=3; (C) c = a & b (C) c = ~a (C) c = b >> 1 a:=1; b:=3 00000001 & 00000011 00000001 ~ 00000001 11111110 00000011 00000001 (C) c = a | b (C) c = a ^ b (C) c = b << 1 00000001 | 00000011 00000011 00000001 ^ 00000011 00000010 00000011 00000110

OPERAO e ou no ou exclusivo shift para direita (diviso por 2) shift para esquerda (multiplicao por 2)

3.10 Operadores de incremento e decremento


Em C e C++ tambm temos os operadores de incremento e decremento: ++ -incremento de um decremento de um

Escrever "m++" ou "++m" quando estes se encontram isolados em uma linha no faz diferena. Quando estiverem sendo usados em conjunto com uma atribuio, entretanto:

Apostila de Linguagem de Programao II

13

Exemplo:
int m, n; m = 5; n = 4; m = n++; Res: m = 4 n = 5 int m, n; m = 5; n = 4; m = ++n; m = 5 n = 5

Obs.: A declarao: printf("%d %d %d",n,n++,n+1); est correta, porm o resultado pode variar de acordo com o compilador dependendo da ordem em que os parmetros so retirados da pilha (stack).

3.11 Operador Condicional


O operador condicional ternrio pode ser utilizado em C e C++ quando o valor de uma atribuio depende de uma condio. O operador ternrio simbolizado pelo operador: Exemplo:
if (x>3) k = k + 1; else k = s - 5;

pode ser substitudo por:

k=(x>3)? k+1: s-5;

3.12 Operador Vrgula


Em C e C++ o operador vrgula avalia duas expresses onde a sintaxe permite somente uma. O valor do operador vrgula o valor da expresso direita. comumente utilizado no lao for, onde mais de uma varivel utilizada. Por exemplo:
for(min=0, max=compr-1; min < max; min++, max--){ ... }

3.13 Tabela de Precedncias dos operadores


Esta a tabela de precedncia dos operadores em C. Alguns (poucos) operadores ainda no foram estudados, e sero apresentados em aulas posteriores.
Maior precedncia () [] -> ! ~ ++ -- . -(unrio) (cast) *(unrio) &(unrio) sizeof */% +<< >> <<= >>= == != & ^ | && || ? = += -= *= /= ,

Menor precedncia

*Uma dica aos iniciantes: Voc no precisa saber toda a tabela de precedncias de cor. E til que voc conhea as principais relaes, mas aconselhvel que ao escrever o seu cdigo, voc tente isolar as expresses com parnteses, para tornar o seu programa mais legvel.

Apostila de Linguagem de Programao II

14

4. COMANDOS DE E/S
A linguagem C no possui nenhum comando de entrada e sada predefinido na linguagem. Todas as operaes de E/S so realizadas por funes que encontram-se nas mais diversas bibliotecas. As principais funes so:

4.1 A funo printf()


A funo printf a funo para sada formatada de dados e funciona da seguinte forma: o primeiro argumento uma string entre aspas (chamada de string de controle) que pode conter tanto caracteres normais como cdigos de formato que comeam pelo caracter de porcentagem. Caracteres normais so apresentados na tela na ordem em que so encontrados. Um cdigo de formato informa a funo printf que um item no caracter deve ser mostrado. Os valores correspondentes encontram-se no segundo argumento (lista de argumentos). SINTAXE: printf(<string de controle>,<lista de argumentos>); Obs.: Alm de cdigos de formato e caracteres normais a string de controle pode conter ainda caracteres especiais iniciados pelo smbolo \. Exemplos:
printf(O preo R$ %d,00,preco); printf(So %d horas e %d minutos., hora, minuto); printf(O nome %s.,nome); printf(%d dividido por %d igual a %f, n1, n2, (float)n1/n2); printf(O cdigo de %c %d, letra, letra);

Cdigos de formato: Normalmente os cdigos de formato so utilizados na sua forma mais simples: %c caracter simples %d decimal %ld inteiro longo %f ponto flutuante %o octal %s cadeia de caracteres %x hexadecima %lf double Obs.: Deve haver uma varivel ou constante para cada cdigo de formato! O tipo das variveis ou constantes tambm deve coincidir com os cdigos de formato.
int a; float b; char c; double d; printf(%d %f %c %lf,a,b,c,d);

Sintaxe completa de um cdigo de formato: %[flags][largura][.preciso][tamanho]<tipo> <tipo> indica o tipo do valor a ser exibido. Listados acima. [flags]: - indica alinhamento pela esquerda + fora os nmeros a comearem por + ou - os negativos ficam com o sinal de - e os positivos com sinal. [largura]: n indica o nmero mximo de casas a ocupar.

um espao em branco no lugar do

Apostila de Linguagem de Programao II

15

0n idntico ao anterior, apenas com a diferena de que as casas no ocupadas sero preenchidas com zeros. [preciso]: n indica o nmero de casas aps a vrgula. [tamanho]: l long Caracteres especiais: Alguns caracteres, como o de tabulao, no possuem representao grfica na tela. Por razes de compatibilidade, a linguagem C fornece constantes iniciadas pelo caracter \ para indicar esses caracteres. \n nova linha \r retorno do carro \t tabulao \b retrocesso (backspace) \ aspas \\ barra \0 nulo \a sinal sonoro \xn caracter de cdigo n (em hexadecimal) Exemplos:
printf(Ol!\n); printf(Linha1\nLinha2\n); printf(\tPargrafo\nHoje %d/%d/%d\n,dia,mes,ano); printf(Este o \\\\ backslach\n); printf(\xB3\n); printf(Ateno!!!\a\a\a Erro!!!\a\n);

4.2 A funo scanf()


a funo de entrada formatada de dados pelo teclado. Sua sintaxe similar da funo printf. scanf(<expr. de controle>, <lista de argumentos>); A expresso de controle pode conter tanto cdigos de formatao precedidos pelo sinal %, que indicam o tipo dos dados a serem lidos, como caracteres de espaamento. a) Cdigos de formato: %c l um caracter %d l um inteiro decimal %e l um nmero em notao cientfica %f l um nmero de ponto flutuante %s l uma string %u l um decimal sem sinal %l l um inteiro longo %lf l um long double %ld l um long int ou long double Sintaxe: [largura][cdigo de formato]

b) Caracteres de Espaamento: So considerados caracteres de espaamento o espao em branco, o caracter \t e o \n. Sempre que um destes surgir na string de controle de um comando scanf ele indicar que o mesmo deve ser considerado como separador dos valores a serem entrados Esses caracteres sero ento lidos pelo scanf, porm, no armazenados.

Apostila de Linguagem de Programao II

16

Normalmente quando o usurio est entrando com valores atendendo a um scanf, quando o mesmo digita um destes caracteres de espaamento, o mesmo lido e no armazenado. A diferena que se o caracter de espaamento aparece na string de controle, ento o scanf n encerrado enquanto o mesmo no for digitado. Toda entrada correspondente um comando scanf deve sempre ser finalizado por <ENTER>. Ex.:
void main(void) { float anos, dias; printf(Digite sua idade em anos: ); scanf(%f,&anos); dias=anos*365; printf(Voc j viveu %f dias\n,dias); }

Obs.: Por enquanto vamos assumir que todas as variveis da lista de argumentos, com exceo das variveis string, devero ser antecedidas do operador &. Mais adiante vamos entender a razo do operador & e quando o mesmo deve ser utilizado. c) Search set possvel ainda, no caso de entradas de strings determinar o conjunto de caracteres vlidos (todos os caracteres que no aparecerem nesse conjunto sero considerados separadores). Sintaxe: %[search set] Exemplos: %[A-Z] todos os caracteres de A at Z %[abc] apenas os caracteres a, b ou c %[^abc] todos os caracteres menos a, b, c %[A-Z0-9a-z] maisculas + minsculas + dgitos

4.3 As funes getche() e getch()


So funes que lem caracteres do teclado sem esperar a tecla <ENTER>. Ambas no recebem argumentos e devolvem o caracter lido para a funo que os chamou. A diferena entre as duas reside no fato de que getche ecoa o caracter lido no vdeo. Exemplo:
void main(void) { char ch; printf(Digite algum caracter: ); ch=getch(); printf(\nA tecla digitada foi %c e seu valor na tabela ASCII % d.,ch,ch); }

Obs.: Devido maneira diferenciada como tratam o buffer de teclado, o uso das rotinas getch e scanf no mesmo programa pode trazer problemas. Para contorn-los, a funo fflush(stdin) garante que o buffer do teclado (stdin - entrada padro) esteja vazio.

4.4 Comandos de Desvio Incondicional


Comandos de desvio incondicional so comandos que alteram a seqncia normal de execuo em um bloco de comandos, transferindo o processamento para um ponto no programa fonte marcado com o rtulo especificado no comando GOTO. EVITE, sempre que possvel comandos GOTO, pois desestruturam completamente um programa, tornando-o muitas vezes ilegvel

Apostila de Linguagem de Programao II

17

Exemplo:

#include <stdio.h> #include <conio.h> #include <ctype.h> char x;

Evite SEMPRE utilizar o goto

void main(void){ clrscr(); inicio: printf("R-Repetir, F-finalizar, Outra tecla- Finalizar de qualquer modo\n"); x=toupper(getch()); if (x=='R') goto inicio; if (x=='F') goto fim_ok; goto fim_qm; fim_ok: printf("Finalizando por bem"); goto fim; fim_qm: printf("Finalizando de qualquer maneira"); fim: getch(); }

4.5 Estruturas de Controle


4.5.1 Seqncia
Seqncia finita de instrues so agrupamentos de comandos, onde cada comando executado um aps o outro e sem desvios. Em C a seqncia delimitada pelos smbolos { no incio e } no final e seus comando tambm so separados pelo delimitador ; (ponto e vrgula).

4.5.2 Comandos condicionais 4.5.2.1 IF


O comando if usado para executar um segmento de cdigo condicionalmente. A forma mais simples do comando if :
if (expresso) ao;

Neste caso a ao somente ser executada se a expresso ou o conjunto de expresses lgicas for verdadeira. No caso do comando if-else o programa pode ter duas aes distintas. Se a expresso for verdadeira, ser executado o conjunto de aes do comando1. Se for falsa ser executado o conjunto de aes do comando2. Implementao do comando if:
if (expresso){ <comando>; } if (expresso){ <comando1>; } else { <comando2>; }

Apostila de Linguagem de Programao II

18

Exemplos em C:
#include <stdio.h> #include <conio.h> int x; void main(void){ x = 10; if (x>15){ printf("X maior que 15\n"); } } #include <stdio.h> #include <conio.h> int x, y; void main(void){ x = 10; y = 20; if (x>15 && y>15){ printf("X e Y so maiores que 15\n"); } else { printf("X e Y no so > que 15\n"); } }

Obs.: Deve-se tomar cuidado com os comando if-else aninhados. O else sempre est associado ao if mais prximo dentro do mesmo nvel de comandos. Blocos mais internos no so considerados. O comando if no necessita de uma expresso lgica no lugar do teste. Em C, qualquer expresso que resultar ZERO ser considerada como FALSA e qualquer outro valor considerado VERDADEIRO. Em Pascal somente aceito os valores booleanos TRUE ou FALSE. Em C tambm temos o comando if else if - else que freqentemente utilizado para executar mltiplas comparaes sucessiva. Sua forma geral :
if (expresso1) ao1; else if (expresso2) ao2; else if (expresso3) ao3;

Logicamente, cada ao poderia ser um bloco composto exigindo seu prprio conjunto de chaves. Este tipo de controle de fluxo lgico avalia a expresso at que encontre uma que VERDADEIRA. Quando isto ocorre, todos os testes condicionais restantes sero desviados. No exemplo anterior, nenhuma ao seria tomada se nenhuma das expresses fosse avaliada como VERDADEIRA. Para executar uma ao padro no caso de no satisfazer nenhuma das expresses declaradas pode-se colocar um else sem expresso de teste para realizar a ao pretendida, por exemplo:
if (expresso1) ao1; else if (expresso2) ao2; else if (expresso3) ao3; else ao_padro;

Exemplo:

#include <stdio.h> #include <conio.h> int x; void main(void){ x = 16; if (x == 5){ printf("X vale 5\n"); } else if (x == 10){

Apostila de Linguagem de Programao II

19

printf("X vale 10\n"); } else if (x == 15){ printf("X vale 15\n"); } else { printf("X no vale 5, 10 ou 15\n"); }

4.5.2.2 Comando de Seleo mltipla: SWITCH ou CASE


Quando se deseja testar uma varivel ou uma expresso em relao a diversos valores usamos o comando de seleo mltipla. O valor da expresso seletora comparado com cada elemento da lista de valores. Se existir um valor igual ser executada somente a seqncia relacionada ao valor. Caso contrrio, ou nenhuma seqncia ser executada, ou a seqncia relacionada clusula padro ser executada se ela existir. Em C devemos tomar um pouco de cuidado, pois o comando switch possui algumas peculiaridades. Sua sintaxe :
switch (expresso) { case <valor1>: <comandos1>; break; case <valor2>: <comandos2>; break; ... case <valor n>: <comandos n>; break; default: <comandos_padro>; }

Exemplo:

#include <stdio.h> #include <conio.h> int x; void main(void){ x = 15; switch(x){ case 5:{ printf("X vale 5\n"); break; } case 10:{ printf("X vale 10\n"); break; } case 15:{ printf("X vale 15\n"); break; } default:{ printf("X nao vale 5, 10 ou 15\n"); } }

Apostila de Linguagem de Programao II

20

getch(); }

Devemos tomar bastante cuidado com o comando obrigatrio break, que faz a poro restante do comando switch ser pulada. Caso ele seja removido do segmento de cdigo, seriam executados todos os comandos abaixo dele.

4.5.3 Comandos de Repetio


Os comandos de repetio so caracterizados por permitir que uam seqncia de comandos seja executada um nmero repetido de vezes.

4.5.3.1 For
O comando for utilizado para executar uma seqncia de comandos repetidamente e com um nmero conhecido de vezes.
for (expr_inicializao; expr_teste; expr_incremento) <comando>;

Exemplos:

for (i=1; i<=10; i++) { printf(%d x 7 = %d \n, i, i*7); } for (i=10; i>=1; i--) { printf(%d x 7 = %d \n, i, i*7); }

Quando o comando de lao for encontrado, a expr_inicializao executada primeiro, no incio do lao, e nunca mais ser executada. Geralmente esse comando fornece a inicializao da varivel de controle do lao. Aps isso testada a expr_teste, que chamada de cndio de trmino do lao. Quando expr_teste avaliada como VERDADEIRA, o comando ou comandos dentro do lao sero executados. Se o lao foi iniciado, expr_incremento executada aps todos os comandos dentro do lao serem executados. Contudo, se exp_teste avaliada como FALSA, os comandos dentro do lao sero ignorados, junto com expr_incremento, e a execuo continua no comando que segue o final do lao. O esquema de endentao para os laos for com diversos comandos a serem repetidos assim:
for (expr_inicializao; expr_teste; expr_incremento){ comando_a; comando_b; comando_c; }

As variveis de controle de um lao de for podem ter seu valor alterado em qualquer ponto do lao. Qualquer uma das expresses de controle do lao de for pode ser omitida desde que sejam mantidos os ;. As variveis utilizadas nas trs expresses de controle no precisam ter relao entre si. Ex.:
void main(void){ char c; int x,y; for(c=9;c>0;c--) { printf(%d,c); } for(c=9;c>0; ) { printf(%d,c); c--;

Apostila de Linguagem de Programao II

21

} for(x=0,y=0; x+y<100; x=x+4, y++) { printf(%d+%d=%d\n,x,y,x+y); } for(;;){ printf(no saio deste lao nunca!!!!\n); } }

4.5.3.2 While
Assim como o lao for, while um lao com teste no inco. Isto significa que a expresso teste avaliada antes dos comandos dentro do corpo do lao serem executados. Por causa disto, os laos com teste no incio podem ser executados de zero a mais vezes. Geralmente estas estruturas so usadas quando um nmero indefinido de repeties esperado.
while (expr_teste) <comandos>;

Exemplo.:
void main(void){ int a, b,ano; a=1500; b=2000; ano=0; while(a<b){ a=a*1.05; b=b*1.02; ano++; } printf(%d anos,ano); }

4.5.3.3 Do While ou Repeat Estes comandos, assim como o comando WHILE, so usados quando no conhecido o nmero de vezes que uma seqncia de comandos dever ser executada. Porm a seqncia ser executada pelo menos uma vez.
A sintaxe do comando :
do <comandos> while(cond_teste);

Exemplo.:
Void main(void){ char a; do { clrscr(); printf(1 - Executar\n); printf(2 - Sair\n); a = getche(); if (a == 1) executar(); } while (a != 2); }

Observe que em Pascal usamos o comando repeat e until fazendo com que o lao repita at que a condio seja satisfeita e em C usamos o comando do e while fazendo com que o lao repita enquanto a condio esteja sendo satisfeita.

Apostila de Linguagem de Programao II

22

4.5.4 Comandos de desvio


Nas linguagem C e Pascal temos os comandos de desvio que interrompem a execuo de um lao.

4.5.4.1 Comando break


O comando break pode ser usado para sair de um lao for, while ou do-while (repeat) mais interno, desde que no mesmo subprograma, passando a seqncia da execuo para a primeira linha aps o lao. Exemplo:
void main(void){ char x, i; for(x=1;x<=100;x++){ printf(Digite um nmero de 0 a 9:); y = getch(); if (y < 48 || y > 57) break; printf(%d foi digitado \n,y); } }

4.5.4.2 Comando continue


O comando continue causa o fim de um dos laos de uma repetio e o retorno imediato ao teste. Exemplo:
void main(void){ int i; for(i=1;i<=10;i++) { if ( i % 2 != 0) continue; printf(O nmero %d par!,i); } }

4.5.4.3 Funo Exit


A funo exit causa a imediata interrupo do programa e o retorno ao sistema operacional. Em C, o valor do parmetro retornado ao processo que o chamou que geralmente o sistema operacional. O valor 0 ( exit(0);) geralmente indica que o processo terminou sem problemas. Exemplo:
#include <stdio.h> #include <conio.h> #include <stdlib.h> void main(void){ while(1) { printf("Xx "); if ( kbhit()) exit(0); } }

4.5.4.4 Comando return


O comando return causa uma interrupo no fluxo de comandos de uma funo e o retorno a funo chamadora. Pode ser usado com ou sem argumento dependento do tipo de funo em que utilizado, porm no possvel em uma nica funo seu uso com e sem argumentos.

Apostila de Linguagem de Programao II

23

5. FUNES E PROCEDIMENTOS
As funes formam o alicerce da programao em C e C++. Conforme vamos aumentando a prtica em programao, os programas comeam a tomar uma aparncia modular quando programamos com funes. Podemos fazer toda a programao em C e C++ dentro de uma funo. Isto porque todos os programas devem incluir main, que uma funo. As funes so similares aos mdulos de outras linguagens. Pascal utiliza procedimentos e funes. Fortran utiliza somente funes, e a linguagem Assembly utiliza somente procedimentos. O modo como as funes trabalham determina o alto grau de eficincia, legibilidade e portabilidade do cdigo do programa em C.

5.1 Funes
Em C uma funo void ou que retorna um valor nulo, pode ser comparada com um procedimento utilizado na linguagem Pascal, porm todas os subprogramas em C so funes e devem retornar um valor (ou retornar void, vazio). 5.2 Estilos e prottipos das funes As declaraes de funo comeam com o prottipo da funo C e C++. O prottipo de funo simples e includo no incio do cdigo do programa para notificar o compilador do tipo e do nmero de argumentos que uma funo utilizar. Embora outras variaes sejam legais, sempre que possvel voc deve utilizar a forma do prottipo de funo que uma rplica da linha de declarao da funo. Por exemplo:
tipo_de_retorno nome_da_funo ( tipo(s)_argumento nome(s)_argumento);

5.2.1 Argumentos das funes


Os argumentos, ou parmetros, passados s funes so opcionais; algumas funes podem no receber argumentos enquanto outras podem receber diversos. Os argumentos podem ser misturados, sendo possvel o uso de qualquer um dos tipos de dados escalares padronizados, podendo ser int, float, double, char e ponteiros. Existem situaes onde necessrio que as sub-rotinas retornem valores calculados internamente. A linguagem C apresenta dois mecanismos para tanto:

5.2.1.1 Passagem de parmetros por valor


As funes recebem parmetros por valor quando na lista de argumentos existem valores ou variveis com valores. Esses argumentos so criados na pilha no momento em que a funo chamada. O comando return permite que uma funo retorne um nico valor. Esse valor obtido na rotina chamadora na medida em que a chamada na funo feita atravs de uma atribuio (Ex. 2). Ex. 1:
... int v; v=30; func1(v,25); {

...

void func1(int a, int b) int x; a = a + 10;

Apostila de Linguagem de Programao II

24

b = b - 10; x = a + b; printf("%d\n",x);

Ex. 2:
void main(void){ float pr, imp; scanf("%f",&pr); imp=calc_imposto(pr); printf("Preo: %f, Imposto: %f\n",pr,imp); } float calc_imposto(float preco); { float imposto; imposto=preco * 0.17; return(imposto); }

No exemplo 1 acima, o valor da varivel v e o valor 25 so passados respectivamente para os argumentos a e b da funo func1. Apesar dos valores de a e b serem alterados dentro da funo, essa mudana no se refletir no valor da varivel v pois o que passado para a funo apenas uma cpia do valor da varivel.

5.2.1.2 Passagem de parmetros por referncia


A passagem de parmetros por referncia faz com que os valores das variveis passadas por referncia sejam alterados dentro da funo. Em C, quando queremos que isto acontea, ao invs de passarmos o valor como parmetro de uma funo, passamos o endereo dessa varivel (que no deixa de ser um valor). O endereo, no caso, faz as vezes de "referncia" para a varivel e nos permite alterar o contedo da mesma dentro da sub-rotina. Ex:
void main(void) { int a; func1(&a); printf("%d",a); } void func1(int *p) { int x; scanf("%d",&x); *p = x * 2; }

Observe que o argumento da funo func1 um ponteiro para inteiro. O que se passa na chamada dessa funo, no o valor da varivel a, mas sim seu endereo (at porque nesse momento a nem ao menos foi inicializado). Dentro da funo func1, o valor digitado pelo usurio multiplicado por 2 e armazenado, no na varivel p que contm o endereo de a, mas na prpria varivel a. Desta forma, quando a funo acaba e o controle volta rotina chamadora, o valor correto j est armazenado em a. Note-se, ento, que o uso de um * antes de uma varivel ponteiro em uma expresso significa que no estamos nos referindo ao valor do ponteiro, mas sim ao valor para o qual aponta. Resumindo, podemos dizer que: &a o endereo de a *p o contedo da varivel apontada por p

Apostila de Linguagem de Programao II

25

5.2.2 Tipos de funes


As funes podem ser: Funes do tipo void: As funes so do tipo void quando indicam explicitamente a ausncia de argumentos na funo. Exemplo.:
#include <stdio.h> #include <math.h> void impressao(void); void main(void){ printf("Este programa extrai uma raiz quadrada\n"); impressao(); return(0); } void impressao(void){ double z=5678.0; double x; x=sqrt(z); printf("A raiz quadrada de %lf %lf\n",z,x); }

Funes do tipo char: As funes so do tipo char quando recebem um caracter como argumento. Exemplo:
#include <stdio.h> #include <conio.h> void impressao(char c); void main(void) { char meucaracter; printf("Informe um caracter pelo teclado\n"); meucaracter=getch(); impressao(meucaracter); } void impressao(char c) { int i; for(i=0;i<10;i++) printf("O caracter : %c\n",c); } }

Funes do tipo int: As funes so do tipo int quando aceitam e retornam um inteiro como argumentos. Funes do tipo long: As funes so do tipo long quando aceitam e retornam long int como argumentos. Funes do tipo float: As funes so do tipo float quando aceitam e retornam float como argumentos. Ex.:
#include <stdio.h> #include <math.h> void hipotenusa(float x, float y); void main(void){ float cateto_y, cateto_x; printf("Altura do tringulo retngulo: "); scanf("%f",cateto_y);

Apostila de Linguagem de Programao II

26

printf("Base do tringulo retngulo: "); scanf("%f",cateto_x); hipotenusa(cateto_y,cateto_x); return(0);

void hipotenusa(float x, float y){ double minhahipo; minhahipo = hipot((double)x,(double)y); printf("A hipotenusa do tringulo : %f\n",minhahipo); }

Funes do tipo double: As funes que aceitam e retornam um tipo double, ou seja um float com muita preciso so do tipo double. Todas as funes que esto definidas em math.h aceitam e retornam tipo double.

5.3 Argumentos passados a programas


Nomalmente as linguagens de programao permitem que o programa receba parmetros passados na linha de comando no momento da sua ativao. Assim, quando usamos o comando format a: ou scan a: passamos o argumento a: para o programa. C e C++ podem aceitar inmeros argumentos da linha de comando. A funo main recebe os parmetros com a seguinte declarao:
main(int argc, char *argv[])

O primeiro argumento um inteiro que fornece o nmero de termos da linha de comando. O nome do programa executvel conta como sendo o primeiro, isto , todo programa ter argc com valor 1 se no tiver nenhum parmetro e valor num_parmetros + 1 quando tiver parmetros. O segundo argumento um ponteiro para as strings argv. Todos os argumentos so strings de caracteres, de modo que so conhecidos no programa como:
argv[1] argv[2] ... primeiro argumento segundo argumento

Ex.: #include <stdio.h> #include <stdlib.h>


void main(int argc, char *argv[]){ int i; if (argc < 2) { printf("Este programa no tem argumentos!"); exit(1); } for (i=1;i < argc; i++) printf("O %d argumento %s\n",i,argv[i]); }

Os argumentos so recebidos da linha de comando e impressos na tela na mesma ordem. Se nmeros forem informados na linha de comando, eles sero interpretados como strings ASCII e impressos como caracteres. Se desejarmos fazer clculos com esses nmeros devemos convert-los de string para nmero com as funes de converso apropriadas (atoi, atol, atof que encontram-se definidas em stdlib.h)

Apostila de Linguagem de Programao II

27

6. VETORES, MATRIZES E STRINGS


6.1 Vetores
Vetores nada mais so que matrizes unidimensionais. Vetores so uma estrutura de dados muito utilizada. importante notar que vetores, matrizes bidimensionais e matrizes de qualquer dimenso so caracterizadas por terem todos os elementos pertencentes ao mesmo tipo de dado. Para se declarar um vetor podemos utilizar a seguinte forma geral:
tipo_da_varivel nome_da_varivel [tamanho];

Quando o C v uma declarao como esta ele reserva um espao na memria suficientemente grande para armazenar o nmero de clulas especificadas em tamanho. Por exemplo, se declararmos: float exemplo [20]; o C ir reservar 4x20=80 bytes. Estes bytes so reservados de maneira contgua. Na linguagem C a numerao comea sempre em zero. Isto significa que, no exemplo acima, os dados sero indexados de 0 a 19. Para acess-los vamos escrever:
exemplo[0] exemplo[1] . . . exemplo[19]

Mas ningum o impede de escrever:


exemplo[30] exemplo[103]

Por qu? Porque o C no verifica se o ndice que voc usou est dentro dos limites vlidos. Este um cuidado que voc deve tomar. Se o programador no tiver ateno com os limites de validade para os ndices ele corre o risco de ter variveis sobreescritas ou de ver o computador travar. Bugs terrveis podem surgir. Vamos ver agora um exemplo de utilizao de vetores:
#include <stdio.h> void main (void){ int num[100]; /* Declara um vetor de inteiros de 100 posicoes */ int count=0; int totalnums; do{ printf ("\nEntre com um numero (-999 p/ terminar): "); scanf ("%d",&num[count]); count++; } while (num[count-1]!=-999); totalnums=count-1; printf ("\n\n\n\t Os nmeros que voc digitou foram:\n\n"); for (count=0;count<totalnums;count++) printf (" %d",num[count]); }

No exemplo acima, o inteiro count inicializado em 0. O programa pede pela entrada de nmeros at que o usurio entre com o Flag -999. Os nmeros so armazenados no vetor num. A cada nmero armazenado, o contador do vetor incrementado para na prxima iterao escrever na prxima posio do vetor. Quando o usurio digita o flag, o programa abandona o primeiro loop e armazena o total de nmeros gravados. Por fim, todos os nmeros so impressos. bom lembrar aqui que nenhuma restrio feita quanto a quantidade de nmeros digitados. Se o usurio digitar mais de 100 nmeros, o programa tentar ler normalmente, mas o programa os escrever em uma parte no alocada de memria, pois o espao alocado foi para somente 100 inteiros. Isto pode resultar nos mais variados erros no instante da execuo do programa.

Apostila de Linguagem de Programao II

28

6.2 Strings (ou Cadeias de Caracteres)


Strings so vetores de chars. Nada mais e nada menos. As strings so o uso mais comum para os vetores. Devemos apenas ficar atentos para o fato de que as strings tm o seu ltimo elemento como um '\0'. A declarao geral para uma string : char nome_da_string [tamanho]; Devemos lembrar que o tamanho da string deve incluir o '\0' final. A biblioteca padro do C possui diversas funes que manipulam strings. Estas funes so teis pois no se pode, por exemplo, igualar duas strings:
string1=string2; /* NAO faca isto */

Fazer isto um desastre. Quando voc terminar de ler a seo que trata de ponteiros voc entender o porqu disso. As strings devem ser igualadas elemento a elemento. Quando vamos fazer programas que tratam de string muitas vezes podemos fazer bom proveito do fato de que uma string termina com '\0' (isto , o nmero inteiro 0). Veja, por exemplo, o programa abaixo que serve para copiar os caracteres de uma string para outra:
#include <stdio.h> void main (void){ int count; char str1[100],str2[100]; .... /* Aqui o programa le str1 que sera copiada para str2 */ for (count=0;str1[count];count++) str2[count]=str1[count]; str2[count]='\0'; .... /* Aqui o programa continua */ }

A condio no loop for acima baseada no fato de que a string que est sendo copiada termina em '\0'. Este tipo de raciocnio a base do C e voc deve fazer um esforo para entender como que o programa acima funciona. Quando o elemento encontrado em str1[count] o '\0', o valor retornado para o teste condicional falso (nulo). Desta forma a expresso que vinha sendo verdadeira (no zero) continuamente, torna-se falsa. Vamos ver agora algumas funes bsicas para manipulao de strings.

6.2.1 gets:
A funo gets() l uma string do teclado. Sua forma geral : gets (nome_da_string); O programa abaixo demonstra o funcionamento da funo gets():
#include <stdio.h> void main (void){ char string[100]; printf ("Digite o seu nome: "); gets (string); printf ("\n\n Ola %s",string); }

Repare que vlido passar para a funo printf() o nome da string. Voc ver mais adiante porque isto vlido. Como o primeiro argumento da funo printf() uma string tambm vlido fazer: printf (string); Isto simplismente imprimir a string.

6.2.2 strcat:
A funo strcat() tem a seguinte forma geral: strcat (string_destino,string_origem); A string de origem permanecer inalterada e ser anexada ao fim da string de destino. Um exemplo:
#include <stdio.h> #include <string.h> void main (void){ char str1[100],str2[100]; printf ("Entre com uma string: ");

Apostila de Linguagem de Programao II

29

gets (str1); strcpy (str2,"Voce digitou a string "); strcat (str2,str1); printf ("\n\n%s",str2);

6.2.3 strcpy:
Sua forma geral : strcpy (string_destino,string_origem); A funo strcpy() copia a string-origem para a string- destino. Seu funcionamento semelhante ao da rotina apresentada na seo anterior. As funes apresentadas nestas sees esto no arquivo cabealho string.h. A seguir apresentamos um exemplo de uso da funo strcpy():
#include <stdio.h> #include <string.h>

void main (void){ char str1[100],str2[100],str3[100]; printf ("Entre com uma string: "); gets (str1); strcpy (str2,str1); strcpy (str3,"Voce digitou a string "); printf ("\n\n%s%s",str3,str2); }

6.2.4 strlen:
Sua forma geral : strlen (string); A funo strlen() retorna o comprimento da string fornecida. O terminador nulo no contado. Isto quer dizer que, de fato, o comprimento do vetor da string deve ser um a mais que o inteiro retornado por strlen (). Um exemplo do seu uso:
#include <stdio.h> #include <string.h> void main (void){ int size; char str[100]; printf ("Entre com uma string: "); gets (str); size=strlen (str); printf ("\n\nA string que voce digitou tem tamanho %d",size); }

6.2.5 Strcmp
Sua forma geral : strcmp (string1,string2); A funo strcmp() compara a string 1 com a string 2. Se as duas forem idnticas a funo retorna zero. Se elas forem diferentes a funo retorna no-zero. Um exemplo da sua utilizao:
#include <stdio.h> #include <string.h> void main (void) { char str1[100],str2[100]; printf ("Entre com uma string: "); gets (str1); printf ("\n\nEntre com outra string: "); gets (str2); if (strcmp(str1,str2)) printf ("\n\nAs duas strings so diferentes."); else printf ("\n\nAs duas strings so iguais."); }

Apostila de Linguagem de Programao II

30

Outras funes encontradas em string.h so apresentadas abaixo: Funo


strcat Strchr strcmp

Sintaxe e Funo
char *strcat(char *dest, const char *src); Adiciona uma cdia da string de origem para o final da string de destino. char *strchr(char *s, int c); Procura numa string a primeira ocorrncia de um caracter. Retorna um ponteiro para a primeira ocorrncia do caracter dentro da string. Se o caracter no for encontrado, strchr retorna NULL.. int strcmp(const char *s1, const char *s2); Compara uma string com outra e retorna: < 0 se s1 for menor que s2 = 0 se s1 for igual s2 > 0 se s1 for maior que s2 char *strcpy(char *dest, const char *src); Copia uma string para outra. Copia string src para dest. Retorna um ponteiro para a string dest. size_t strcspn(const char *s1, const char *s2); Procura em s1 at que qualquer um dos caracteres contidos em s2 encontrado. O nmero de caracteres que so lidos em s1 o valor retornado. int stricmp(const char *s1, const char *s2); Compara uma string com outra sem distino entre maiscula e minscula e retorna: < 0 se s1 for menor que s2 = 0 se s1 for igual s2 > 0 se s1 for maior que s2 size_t strlen(const char *s); Calcula e retorna o tamanho de uma string. char *strlwr(char *s); Converte letras maisculas em minsculas numa string. char *strncat(char *dest, const char *src, size_t n); Adiciona uma poro de uma string a outra. strncat copia n caracteres de src para o final de dest e acrescenta um caractere NULL. int strncmp(const char *s1, const char *s2, size_t n); Compara uma poro de uma string com uma poro de outra string. strncmp faz a mesma comparao que strcmp, mas analisa no mximo os n primeiros caracteres e retorna: < 0 se s1 for menor que s2 = 0 se s1 for igual s2 > 0 se s1 for maior que s2 char *strncpy(char *dest, const char *src, size_t n); Copia um um determinado nmero de bytes (n) de uma string para outra.. int strnicmp(const char *s1, const char *s2, size_t n); Compara uma poro de uma string com uma poro de outra string sem distino de maisculas com minsculas. strncmp faz o mesmo, mas analisa no mximo os n primeiros caracteres. Retorna: < 0 se s1 for menor que s2 = 0 se s1 for igual s2 > 0 se s1 for maior que s2 char *strnset(char *s, int ch, size_t n); Altera os n primeiros caracters de uma string para um caractere especfico (ch). char *strrchr(const char *s, int c); Procura numa string pela ltima ocorrncia de um caracter (c). char *strrev(char *s); Reverte uma string. strrev muda todos os caracteres numa string para a ordem reversa, com exeo do caracter nulo de terminao. char *strset(char *s, int ch); Altera todos os caracteres numa string para um determinado caracter (ch). size_t strspn(const char *s1, const char *s2); Procura numa string s1 pelo primeiro segmento que difere de s2, retornando a posio onde inicia a diferena. char *strstr(const char *s1, const char *s2); Procura numa string s1 pela ocorrncia de uma dada substring s2. char *strupr(char *s); Converte letras minsculas numa string para maisculas

strcpy strcspn stricmp

strlen strlwr strncat strncmp

strncpy strnicm p

strnset strrchr strrev strset strspn strstr strupr

Apostila de Linguagem de Programao II

31

6.3 Matrizes
6.3.1 Matrizes bidimensionais
J vimos como declarar matrizes unidimensionais (vetores). Vamos tratar agora de matrizes bidimensionais. A forma geral da declarao de uma matriz bidimensional muito parecida com a declarao de um vetor:
tipo_da_varivel nome_da_varivel [altura][largura];

muito importante ressaltar que, nesta estrutura, o ndice da esquerda indexa as linhas e o da direita indexa as colunas. Quando vamos preencher ou ler uma matriz no C o ndice mais direita varia mais rapidamente que o ndice esquerda. Mais uma vez bom lembrar que, na linguagem C, os ndices variam de zero ao valor declarado, menos um; mas o C no vai verificar isto para o usurio. Manter os ndices na faixa permitida tarefa do programador. Abaixo damos um exemplo do uso de uma matriz:
#include <stdio.h> void main (void){ int mtrx [20][10]; int i,j,count; count=1; for (i=0;i<20;i++) for (j=0;j<10;j++) { mtrx[i][j]=count; count++; } }

No exemplo acima, a matriz mtrx preenchida, sequencialmente por linhas, com os nmeros de 1 a 200. Voc deve entender o funcionamento do programa acima antes de prosseguir.

6.3.2 Matrizes de strings


Matrizes de strings so matrizes bidimensionais. Imagine uma string. Ela um vetor. Se fizermos um vetor de strings estaremos fazendo uma lista de vetores. Esta estrutura uma matriz bidimensional de chars. Podemos ver a forma geral de uma matriz de strings como sendo: char nome_da_varivel [num_de_strings][compr_das_strings]; A surge a pergunta: como acessar uma string individual? Fcil. s usar apenas o primeiro ndice. Ento, para acessar uma determinada string faa: nome_da_varivel [ndice] Aqui est um exemplo de um programa que l 5 strings e as exibe na tela:
#include <stdio.h> void main (void){ char strings [5][100]; int count; for (count=0;count<5;count++){ printf ("\n\nDigite uma string: "); gets (strings[count]); } printf ("\n\n\nAs strings que voce digitou foram:\n\n"); for (count=0;count<5;count++) printf ("%s\n",strings[count]); }

6.3.3 Matrizes multidimensionais


O uso de matrizes multidimensionais na linguagem C simples. Sua forma geral : tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN];

Apostila de Linguagem de Programao II

32

Uma matriz N-dimensional funciona basicamente como outros tipos de matrizes. Basta lembrar que o ndice que varia mais rapidamente o ndice mais direita. a) Inicializao Podemos inicializar matrizes, assim como podemos inicializar variveis. A forma geral de uma matriz como inicializao : tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN] = {lista_de_valores}; A lista de valores composta por valores (do mesmo tipo da varivel) separados por vrgula. Os valores devem ser dados na ordem em que sero colocados na matriz. Abaixo vemos alguns exemplos de inicializaes de matrizes:
float vect [6] = { 1.3, 4.5, 2.7, 4.1, 0.0, 100.1 }; int matrx [3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; char str [10] = { 'J', 'o', 'a', 'o', '\0' }; char str [10] = "Joao"; char str_vect [3][10] = { "Joao", "Maria", "Jose" };

O primeiro demonstra inicializao de vetores. O segundo exemplo demonstra a inicializao de matrizes multidimensionais, onde matrx est sendo inicializada com 1, 2, 3 e 4 em sua primeira linha, 5, 6, 7 e 8 na segunda linha e 9, 10, 11 e 12 na ltima linha. No terceiro exemplo vemos como inicializar uma string e, no quarto exemplo, um modo mais compacto de inicializar uma string. O quinto exemplo combina as duas tcnicas para inicializar um vetor de strings. Repare que devemos incluir o ; no final da inicializao. b) Inicializao sem especificao de tamanho Podemos, em alguns casos, inicializar matrizes das quais no sabemos o tamanho a priori. O compilador C vai, neste caso verificar o tamanho do que voc declarou e considerar como sendo o tamanho da matriz. Isto ocorre na hora da compilao e no poder mais ser mudado durante o programa, sendo muito til, por exemplo, quando vamos inicializar uma string e no queremos contar quantos caracteres sero necessrios. Alguns exemplos:
char mess [] = "Linguagem C: flexibilidade e poder."; int matrx [][2] = { 1,2,2,4,3,6,4,8,5,10 };

No primeiro exemplo, a string mess ter tamanho 36. No segundo exemplo o valor no especificado ser 5.

6.3.4 Matrizes e vetores como parmetros de funes


Como j se viu anteriormente, uma funo em C s aceita parmetros por valor. No possvel, portanto, passar um vetor ou matriz (tipos de dados estruturados) como parmetro. A soluo utilizada quando da necessidade de se trabalhar com os dados contidos em um vetor no global dentro de uma funo passar um ponteiro para este vetor como parmetro. Para trabalhar com os elementos do vetor dentro da funo procede-se de forma normal j que sempre que estamos trabalhando com vetores estamos usando um ponteiro para a primeira posio da rea de memria alocada para o mesmo. Exemplo de passagem de parmetro por valor de um vetor :
#include <stdio.h> #include <conio.h> void imprime(int vet2[10]); void main(void){ int a, vet[10]; clrscr(); for (a=0;a<10;a++) scanf("%d",&vet[a]); imprime(vet); getch(); }

void imprime(int vet2[10]){ int a; for (a=0;a<10;a++) printf("%d ",vet2[a]); }

Apostila de Linguagem de Programao II

33

Exemplo de passagem de parmetro por referncia de um vetor :


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

void imprime(int *vet2, int n); void main(void){ int a, vet[10]; clrscr(); for (a=0;a<10;a++) scanf("%d",&vet[a]); imprime(vet,10); getch(); } void imprime(int *vet2, int n){ int a; for (a=0;a<n;a++) printf("%d ",vet2[a]); }

Exemplo de passagem de passagem de parmetro por valor de uma matriz:


#include <stdio.h> #include <conio.h> void imprime(int mat2[3][3]); void main(void){ int i, j, mat[3][3]; clrscr(); for (i=0;i<3;i++) for (j=0;j<3;j++) scanf("%d",&mat[i][j]); imprime(mat); getch(); }

void imprime(int mat2[3][3]){ int a, b; for (a=0;a<3;a++) { printf("\n"); for (b=0;b<3;b++) printf("%d ",mat2[a][b]); } }

Exemplo de passagem de passagem de parmetro por referncia de uma matriz. No caso de matrizes, pelo menos uma das dimenses tem que ser conhecida.
#include <stdio.h> #include <conio.h> void imprime(int mat2[][3], int l); void main(void){ int i, j, mat[3][3]; clrscr(); for (i=0;i<3;i++){ for (j=0;j<3;j++) scanf("%d",&mat[i][j]); } imprime(mat,3); }

void imprime(int mat2[][3], int linha){ int a, b; for (a=0;a<linha;a++) { printf("\n"); for (b=0;b<3;b++) printf("%d ",mat2[a][b]); } }

Apostila de Linguagem de Programao II

34

7.PONTEIROS
ints guardam inteiros. floats guardam nmeros de ponto flutuante. chars guardam caracteres. Ponteiros guardam endereos de memria. Quando voc anota o endereo de um colega voc est criando um ponteiro. O ponteiro este seu pedao de papel. Ele tem anotado um endereo. Qual o sentido disto? Simples. Quando voc anota o endereo de um colega, depois voc vai usar este endereo para achlo. O C funciona assim. Voc anota o endereo de algo numa varivel ponteiro para depois usar. Da mesma maneira, uma agenda, onde so guardados endereos de vrios amigos, poderia ser vista como sendo uma matriz de ponteiros no C.
#include <stdio.h> void main(void){ int cont=10; int *pt; pt = &cont; printf("%d",*pt); }

Na verdade, na definio de um ponteiro para inteiro, (int *pt; por exemplo), utiliza-se dois espaos de memria:
pt = FFF4 &pt = FFF2 *pt = 8 &(*pt) = FFF4

FFF0

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

FFF4

FFF4

void main(void){ clrscr(); int num = 55, valor; int *p; p = &num; valor = *p; printf(" %d: ",valor); printf("\n Endereco para onde o ponteiro aponta: %p ",p); printf("\n Valor da variavel apontada: %d \n",*p); getch(); } void main(void){ clrscr(); int num = 55, *p; p = &num; printf("Valor inicial de num: %d \n ",num); *p=100; printf("Valor final de num: %d ",num); getch(); }

Podemos fazer algumas operaes aritmticas com ponteiros. A primeira, e mais simples, igualar dois ponteiros. Se temos dois ponteiros p1 e p2 podemos igual-los fazendo p1=p2. Repare que estamos

Apostila de Linguagem de Programao II

35

fazendo com que p1 aponte para o mesmo lugar que p2. Isso diferente de igualar ponteiro a varivel comum. Nesse caso, o & (&cont) necessrio:
int cont=10; int *pt; pt = &cont; void main(void){ clrscr(); int *p1,*p2; *p2=5; p1 = p2; printf("\nValor de p1: %d ",*p1); printf("\nEndereco de p1: %p",p1); printf("\nEndereco de p2: %p",p2); getch(); }

Se quisermos que a varivel apontada por p1 tenha o mesmo contedo da varivel apontada por p2 devemos fazer *p1=*p2.
void main(void){ clrscr(); int *p1,*p2; *p2 = 5; *p1 = *p2; printf("\nValor de printf("\nValor de printf("\nEndereco printf("\nEndereco getch(); }

p1: %d p2: %d de p1: de p2:

",*p1); ",*p2); %p",p1); %p",p2);

Quando incrementamos um ponteiro ele passa a apontar para o prximo valor do mesmo tipo para o qual o ponteiro aponta. Isto , se temos um ponteiro para um inteiro e o incrementamos ele passa a apontar para o prximo inteiro. Esta mais uma razo pela qual o compilador precisa saber o tipo de um ponteiro: se voc incrementa um ponteiro int* ele anda 2 bytes na memria e se voc incrementa um ponteiro double* ele anda 8 bytes na memria. O decremento funciona semelhantemente. Supondo que p um ponteiro, as operaes so escritas como: p1++; p2--;
#include <stdio.h> #include <conio.h> void main(void){ clrscr(); int *p1,*p2; p2 = p1++; printf("\nValor de printf("\nValor de printf("\nEndereco printf("\nEndereco getch(); }

p1: %d p2: %d de p1: de p2:

",*p1); ",*p2); %p",p1); %p",p2);

Mais uma vez insisto. Estamos falando de operaes com ponteiros e no de operaes com o contedo das variveis para as quais eles apontam. Por exemplo, para incrementar o contedo da varivel apontada pelo ponteiro p, faz-se: (*p)++; Outras operaes aritmticas teis so a soma e subtrao de inteiros com ponteiros. Vamos supor que voc queira incrementar um ponteiro de 15. Basta fazer: p=p+15; ou p+=15; E se voc quiser usar o contedo do ponteiro 15 posies adiante:
*(p+15);

Apostila de Linguagem de Programao II

36

7.1 Ponteiros para matrizes


Ponteiros e matrizes esto intimamente relacionados. O nome de uma matriz uma constante cujo valor representa o endereo do primeiro elemento da matriz. Por esta razo, um comando de atribuio ou qualquer outro comando no pode modificar o valor do nome de uma matriz.Com as declaraes: float classe[10]; float *float_ptr; o nome da matriz classe uma constante cujo valor o endereo do primeiro elemento da matriz de 10 floats. O comando a seguir atribui o endereo do primeiro elemento da matriz varivel ponteiro float_ptr: float_ptr = classe Um comando equivalente : float_ptr = &classe[0]; Entretanto, como float_ptr contm o endereo de um float, os seguintes comandos so ilegais pois tentam atribuir um valor para a constante classe ou seu equivalente &classe[0]: classe = float_ptr; &classe[0] = float_ptr;

7.2 Ponteiros para ponteiros


Em C podemos definir variveis ponteiro que apontam para outra varivel ponteiro, que, por sua vez, aponta para os dados. Isto necessrio para programao em ambientes operacionais multitarefa, como Windows, Windows NT e OS/2 que foram projetados para maximizar o uso da memria. Para compactar o uso da memria, o sistema operacional precisa ser capaz de mover objetos na memria quando necessrio. Se seu programa aponta diretamente para a clula de memria fsica onde o objeto est armazenado, e o sistema operacional o mover, haver desastre. Em vez disso, sua aplicao aponta para o endereo da clula de memria que no ser modificada enquanto o programa estiver sendo executado (um endereo virtual), e a clula de memria endereo_virtual mantm o endereo_fsico_atual do objeto de dados, atualizada automaticamente pelo sistema operacional. Para definir um ponteiro para um ponteiro em C, simplesmente aumenta-se o nmero de asteriscos que precedem o identificador como por exemplo: char **char_ptr; Neste exemplo, a varivel char_ptr definida como um ponteiro para um ponteiro que aponta para um tipo de dados char. Cada asterisco lido como ponteiro para. O nmero de ponteiros que precisa ser seguido para acessar o item de dados, ou o nmero de asteriscos que deve ser colocado na varivel para referenciar o valor ao qual ela aponta, chamado de nvel de indireo da varivel ponteiro. O nvel de indireo de um ponteiro determina quanta desreferenciao deve ser feita para acessar o tipo de dados na definio. Observe o exemplo: int int_dados = 5; int *int_ptr1; int **int_ptr2; int ***int_ptr3; int_ptr1 = &int_dados; int_ptr2 = &int_ptr1; int_ptr3 = &int_ptr2;

Apostila de Linguagem de Programao II

37

int_dado 5
[1112]

int_ptr1 1112
[2368]

int_ptr2 2368
[3219]

int_ptr3 3219

7.3 Aritmtica com ponteiros


Em C tambm possver a realizao de aritmtica com ponteiros, fazendo-se adio e subtrao com variveis do tipo ponteiro. Ex.:
int *ptr_int; float *ptr_float; int um_inteiro; float um_float; ptr_int = &um_inteiro; ptr_float = &um_float; ptr_int++; ptr_float++;

Observe apenas que se o valor de ptr_int antes do incremento fosse 2000, aps o incremento esse valor passou para 2002, pois um incremento de int corresponde a 2 bytes, da mesma forma que ptr_float passaria de 3000 para 3004.

7.4 Ponteiros para funes


Em C possvel que uma funo seja ativada atravs de seu endereo de colocao em memria, ao invs de seu nome. Desta forma, pode-se declarar um ponteiro para uma funo (um varivel que armazena o endereo de uma funo) e evoc-la atravs desse ponteiro. Exemplo.: int (*ptr_func)();

Neste caso, ptr_func um ponteiro para uma funo que retorna inteiro e no possui parmetros. Se, por exemplo, o programa contiver uma funo chamada calcula: int calcula(void);

ptr_func ir armazenar o endereo de calcula se fizermos:


ptr_func = calcula; /*observe que nao calcula() */

A funo ativada atravs do ponteiro quando se escreve: (*ptr_func)(); Outros exemplos: void (*func)(int);

func um ponteiro para uma funo void que possui um inteiro como parmetro; float (*ptf)(int,double); ptf um ponteiro para uma funo que retorna float e possui como parmetros um int e um double.
Os ponteiros para funes tm importantes usos. Por exemplo, considere a funo qsort (ordena um vetor), que tem como um de seus parmetros um ponteiro para uma funo. Ns no podemos passar uma funo

Apostila de Linguagem de Programao II

38

por valor, isto , passar o prprio cdigo, mas podemos passar um ponteiro para o cdigo, ou seja, um ponteiro para a funo. Exemplos:
#include <stdio.h> int soma(int a, int b); int sob(int a, int b); void main(void) { int (*pf)(int,int); /* ponteiro para funo /* int i, a, b, r; for(i=0;i<4;i++){ if=(i%2==0)?soma:sub; printf(\nDigite um valor: ); scanf(%d,&a); printf(\nDigite outro valor: ); scanf(%d,&b); r=(*pf)(a,b); printf(%d\n, r); } } int soma(int a, int b) { printf(A soma : \n); return(a+b); } int sub(int a, int b) { printf(A subtrao : \n); return(a-b); }

Outro caso tpico de aplicao so os vetores de ponteiros para funes:


#include <stdio.h> void zero(); void um(); void dois(); void main(void) { void (*vet[3])(); /* vetor de ponteiros para funes */ int op; vet[0] = zero; vet[1] = um; vet[2] = dois; do { printf(Digite um nmero entre 0 e 2: ); scanf(%d,&op); (*vet[op])(); } while (op<0 || op>2); } void zero(){ printf(Zero!\n); } void um() { printf(Um!\n); } void dois() { printf(Dois!\n); }

Apostila de Linguagem de Programao II

39

8. ESTRUTURAS, UNIES E ITENS DIVERSOS


8.1 Estruturas
Ns podemos pensar em estruturas como sendo uma matriz ou um vetor de itens intimamente relacionados. Entretanto, ao contrrio da matriz ou vetor, uma estrutura permite que se armazene diferentes tipos de dados. O conceito de estrutura de dados comum no dia-a-dia. Um arquivo de fichas com informaes sobre o cliente uma estrutura de itens relacionados. Ns podemos criar uma estrutura usando a palavra-chave struct e a seguinte sintaxe:
struct tipo { tipo var1; ... tipo varn; } var_tipo,...;

Por exemplo se queremos criar uma estrutura (tipo definido pelo usurio) cadastro e definirmos uma varivel cliente que do tipo (estrutura) cadastro:
#include <stdio.h> #include <conio.h>

struct cadastro { char nome[30]; char endereco[50]; char cidade[20]; } cliente; void main(void) { printf(Nome: ); gets(cliente.nome); printf(Endereo: ); gets(cliente.endereco); printf(Cidade: ); gets(cliente.cidade); clrscr(); printf(%s mora na rua %s, na cidade de %s, cliente.nome, cliente.endereco,cliente.cidade); }

8.2 Passando uma estrutura para uma funo


Podem ocorrer situaes que teremos que passar informaes de estruturas para funes. Quando uma estrutura passada para uma funo, as informaes da estrutura so passadas por valor, e assim a funo no altera a estrutura original. Por exemplo se a impresso dos dados do exemplo anterior fosse passada para uma funo:
#include <stdio.h> #include <conio.h> struct cadastro { char nome[30]; char endereco[50]; char cidade[20]; }; void imprime(struct cadastro pessoas); void main(void) { struct cadastro cliente printf(Nome: ); gets(cliente.nome); printf(Endereo: );

Apostila de Linguagem de Programao II

40

gets(cliente.endereco); printf(Cidade: ); gets(cliente.cidade); imprime(cliente);

void imprime(struct cadastro pessoas){ clrscr(); printf(%s mora na rua %s, na cidade de %s, pessoas.nome, pessoas.endereco, pessoas.cidade); }

8.2.1 Matriz de Estruturas


Podemos criar uma matriz de estruturas, o que semelhante a um fichrio que contm diversas fichas de clientes. Por exemplo:
#include <stdio.h> #include <conio.h>

struct cadastro { char nome[30]; char endereco[50]; char cidade[20]; } cliente[5]; void main(void) { int i; for(i=0;i<5;i++){ printf(Nome: ); gets(cliente[i].nome); printf(Endereo: ); gets(cliente[i].endereco); printf(Cidade: ); gets(cliente[i].cidade); } clrscr(); for(i=0;i<5;i++) { printf(%s mora na rua %s, na cidade de %s \n, cliente[i].nome, cliente[i].endereco, cliente[i].cidade); } }

8.2.2 Estruturas dentro de estruturas


Podemos aninhar estruturas, isto , tornar uma estrutura parte de uma segunda estrutura. Por exemplo:
#include <stdio.h> #include <conio.h> struct int int int }; data { dia; mes; ano;

struct cadastro { char nome[30]; char endereco[50]; char cidade[20]; struct data dnasc; }; void main(void) { int i; cadastro cliente[5];

Apostila de Linguagem de Programao II

41

for(i=0;i<5;i++){ printf("Nome: "); gets(cliente[i].nome); printf("Endereo: "); gets(cliente[i].endereco); printf("Cidade: "); gets(cliente[i].cidade); fflush(stdin); printf("Data de Nascimento: "); scanf("%d%d%d", &cliente[i].dnasc.dia, &cliente[i].dnasc.mes, &cliente [i].dnasc.ano); fflush(stdin); } clrscr(); for(i=0;i<5;i++){ printf("%s mora na rua %s, na cidade de %s\n", cliente[i].nome, cliente [i].endereco,cliente[i].cidade); printf("E nasceu no dia %d/%d/%d\n", cliente[i].dnasc.dia, cliente[i]. dnasc.mes, cliente[i].dnasc.ano); } }

8.2.3 Ponteiros para estruturas


A utilizao de ponteiros para estruturas uma tcnica to comum que um novo operador, conhecido cmo operador seta pelos programadores de C, foi desenvolvido, e tem este aspecto: -> . Em outras palavras, se definirmos uma estrutura denominada meus_dados que seja semelhante a:
struct grande_estrutura_dados{ int chave; int grande_vetor[20]; } meus_dados;

Ento poderemos declarar um ponteiro denominado meu_ponteiro para meus_dados como este:
struct grande_estrutura_dados *meu_ponteiro;

E atribuir um valor a ele desta forma:


meu_ponteiro = &meus_dados; meu_ponteiro->chave = 5; meus_dados.chave = 5;

A partir de agora, podemos nos referir aos campos em meus_dados como meus_dados.chave, como: o mesmo que o comando a seguir: Em outras palavras, meu_ponteiro um ponteiro para uma estrutura; para alcanar um campo na estrutura para a qual ele aponta, utilize o operador seta, ->. Essa a razo pela qual o operador -> foi desenvolvido: para permitir escolher campos isolados da estrutura que est sendo apontada. Foram includos os operadores * e & expressamente para aqueles casos em que apontamos para uma estrutura, porque & ou * sozinhos no podem acessar elementos. Ou seja, no existe algo como *meu_ponteiro.chave; temos que utilizar em seu lugar meu_ponteiro->chave. Uma estrutura somente pode ser passada para uma funo por referncia, atravs de um ponteiro para a estrutura. Por exemplo:
#include <stdio.h> #include <conio.h> struct produto { int codigo; char descr[80]; float preco; }p1, p2;

Apostila de Linguagem de Programao II

42

void leprod(produto *ptr); void imprimeprod(produto *ptr); void main(void){ leprod(&p1); leprod(&p2); clrscr(); imprimeprod(&p1); imprimeprod(&p2); getch(); } void leprod(produto *ptr){ int aux; float aux2; fflush(stdin); printf("Codigo: "); scanf("%d",&aux); ptr->codigo = aux; fflush(stdin); printf("Descricao: "); gets(ptr->descr); printf("Preco: "); scanf("%f",&aux2); ptr->preco = aux2; } void imprimeprod(produto *ptr) { printf("%d\n",ptr->codigo); puts(ptr->descr); printf("%0.2f\n",ptr->preco); }

8.2.4 Enumeraes
Numa enumerao podemos dizer ao compilador quais os valores que uma determinada varivel pode assumir. Sua forma geral : enum nome_do_tipo_da_enumerao {lista_de_valores} lista_de_variveis; Vamos considerar o seguinte exemplo:
enum dias_da_semana {segunda, terca, quarta, quinta, sexta, sabado,domingo};

O programador diz ao compilador que qualquer varivel do tipo dias_da_semana s pode ter os valores enumerados. Isto quer dizer que poderamos fazer o seguinte programa:
#include <stdio.h> enum dias_da_semana {segunda, terca, quarta, quinta, sexta, sabado, domingo}; void main (void){ enum dias_da_semana d1,d2; d1=segunda; d2=sexta; if (d1==d2) printf ("O dia e o mesmo."); else printf ("So dias diferentes."); return 0; }

Voc deve estar se perguntando como que a enumerao funciona. Simples. O compilador pega a lista que voc fez de valores e associa, a cada um, um nmero inteiro. Ento, ao primeiro da lista, associado o nmero zero, o segundo ao nmero 1 e assim por diante. As variveis declaradas so ento variveis int.

Apostila de Linguagem de Programao II

43

9. ARQUIVOS Para comearmos a manipular arquivos, necessitamos lembrar alguns conceitos bsicos a respeito dos mesmos. Quando pensamos em arquivos, a primeira coisa que nos vem memria a idia de um arquivo fsico igual aos arquivos encontrados nos escritrios. De forma geral um arquivo serve para armazenar informaes atravs de fichas. Em informtica, estes conceitos so perfeitamente vlidos, pois para o armazenamento de informaes em um arquivo, temos que dar uma forma ao arquivo e dar forma s informaes que estaro contidas nele. Um arquivo em C no possui a idia de registro. Podemos gravar dados no formato de caracter (ASCII) ou em binrio (binary file). A seqncia e interpretao dos dados de inteira responsabilidade do programador do sistema. Um arquivo em C uma seqncia contnua de butes gravados em memria secundria. Cada byte do arquivo possui um endereo nico que o deslocamento relativo ao incio do arquivo. Toda a manipulao de arquivos realizada atravs de funes de biblioteca. Existem dois nveis de funes: as rotinas de baixo nvel - mais eficientes, que utilizam diretamente os recursos do sitema operacional - e as de alto nvel - mais fceis de serem utilizadas - construdas sobre as funes de baixo nvel. Para as rotinas de alto-nvel, os arquivos so acessados atravs de ponteiros para estruturas do tipo FILE, definidas em stdio.h. Para as rotinas de baixo nvel os arquivos so identificados por um nmero inteiro que o cdigo identificador do arquivo retornado pelo sistema operacional (file handle). Na estrutura FILE, o nmero identificador do arquivo o campo fd. As rotinas de alto-nvel possuem por sua vez dois conjuntos de rotinas: rotinas para manipulao de arquivos texto e rotinas para manipulao de arquivos binrios. A diferena bsica entre os dois conjuntos que as rotinas de manipulao de arquivos binrios armazenam uma cpia dos bytes da memria principal para a secundria enquanto que as de manipulao de arquivos texto armazenam a representao ASCII dos valores. Principais rotinas de baixo nvel (prototipadas em io.h) access - Verifica se um arquivo existe e se pode ser lido/gravado. chmod - Modifica os atributos de um arquivo. close - Fecha um arquivo. creat - Cria um arquivo. Est em desuso eof - Verifica se a leitura chegou ao final de um arquivo. filelenght - Informa o tamanho de um arquivo. getftime - Informa a data de criao/acesso de um arquivo. lock - Coloca um arquivo em uso exclusivo. utilizada para fazer controle de acesso concorrente em ambiente multi-usurio ou de rede. Lseek - Descola o ponteiro de leitura para um byte especfico no arquivo. open - Abre/cria um arquivo. read - L dados de um arquivo. tell - Informa em qual byte est o ponteiro do arquivo. unlock - Libera o arquivo do uso exclusivo. write - Escreve dados em um arquivo. Principais rotinas de alto nvel: fclose - Fecha um arquivo. feof - Informa se a leitura chegou ao fim de arquivo. fflush - Esvazia o buffer do arquivo. fgetc - L um caracter de um arquivo. fgets - L uma string de um arquivo.

Apostila de Linguagem de Programao II

44

fputc fputs fread fscanf fseek ftell fwrite remove rename setvbuf fflushall fprintf

- Escreve um caracter em um arquivo. - Escreve uma string em um arquivo. - L dados de um arquivo. - L dados de um arquivo, como scanf - Desloca o ponteiro do arquivo para um determinado byte. - Indica em qual byte se localiza o ponteiro do arquivo. - Escreve em um arquivo. - Remove um arquivo. - Muda o nome de um arquivo. - Modifica o tamanho interno do buffer do arquivo. - Descarrega o buffer de todos os arquivos. - Escreve em um arquivo, no mesmo formato que printf.

Obs: Existem cinco arquivos tipo stream pr-definidos que so automaticamente abertos quando um programa entra em execuo: stdin - Dispositivo padro de entrada (geralmente teclado). stdout - Dispositivo padro de sada (geralmente vdeo). stderr - Dispositivo padro para sada de erros. stdaux - Dispositivo auxiliar (porta serial, por exemplo). stdprn - Impressora padro do sistema. Exemplo:
printf(%d,x);

o mesmo que
fprintf(stdout, %d, x);

9.1 Declarao de arquivos


Quando se usa o conjunto de rotinas de alto nvel, utilizam-se ponteiros do tipo FILE para armazenar uma referncia para um arquivo. FILE na verdade uma estrutura que guarda uma srie de informaes sobre o arquivo. Uma estrutura desse tipo alocada pela rotina fopen e uma referncia para a mesma deve ser armazenada. Exemplo:
FILE *arq, *arq1;

9.2 Funes de abertura e fechamento de arquivos


A funo fopen usada para a abertura de arquivos tanto no modo texto como no modo binrio. Em seus parmetros devemos indicar o nome com o qual o arquivo (ou ser) identificado no dispositivo de memria secundria e o modo que se deseja trabalhar com o mesmo (leitura, escrita, alterao, etc). A funo fopen retorna um ponteiro para a estrutura do tipo FILE que descreve o arquivo. Funo fopen Sintaxe:
arq1 = fopen("clientes.dat","ab+");

onde: arq1 = ponteiro para o arquivo; clientes.dat = nome do arquivo no disco; ab+ = indica o modo de abertura do arquivo: modos: w abre/cria para escrita. Se j existe, destrudo. r abre somente para leitura.

Apostila de Linguagem de Programao II

45

a abre o arquivo para escrita a partir do fim do mesmo ou cria se o arquivo no existir. r+ abre um arquivo j existente tanto para leitura como para gravao. Se este arquivo j existir ele no ser destrudo. w+ abre um arquivo tanto para leitura como para gravao. Se este arquivo j existir ele ser destrudo. a+ abre um arquivo para leitura/gravao ao final do arquivo. Se o arquivo no existe ele criado. No MS-DOS ainda h como segundo caracter de modo as opes: b especifica que o arquivo binrio t especifica que o arquivo texto A funo fopen retorna NULL se no puder abrir/criar o arquivo. Exemplo:
... char narq[20];

arq1 = fopen(texto.txt,wt); if (arq1 == NULL) printf(No consegui abrir o arquivo\n); strcpy(narq,dados); arq2 = fopen(narq,rb); if (arq2 == NULL) printf(No consegui abrir o arquivo %s,narq); ...

Funo fclose A funo fclose deve ser usada toda a vez que no for mais necessrio trabalhar com um arquivo. Libera os buffers alocados pelo sistema operacional para o gerenciamento do arquivo garantindo que todos os dados so efetivamente descarregados no dispositivo de memria secundria. Libera tambm a estrutura do tipo FILE. Sintaxe:
fclose <fstream>

onde: fstream = ponteiro para o arquivo Exemplo:


fclose(arq1); fclose(arq2);

9.3 Funes de escrita e gravao para arquivo binrio


Funo fwrite A funo fwrite copia uma poro da memria principal para um dispositivo de memria secundria. Recebe como parmetros o endereo do incio da rea e a quantidade de bytes a ser copiada. Sintaxe:
fwrite(<ptr>, <tamanho>, <nro>, <fstream>);

onde: ptr = ponteiro para o incio dos dados a serem gravados tamanho = tamanho do registro lgico; nro = quantidade de registros lgicos (registro fsico = nro x tamanho); fstream = ponteiro para o arquivo; fwrite retorna o nmero de itens que conseguiu gravar no arquivo. Funo fread

Apostila de Linguagem de Programao II

46

A funo fread tem a funo inversa da funo fwrite carregando um conjunto de bytes do dispositivo de memria secundria para a memria principal. Possui os mesmos parmetros que fwrite porm com o sentido inverso. Sintaxe
fread(<ptr>, <tamanho>, <nro>, <fstream>);

onde: ptr = ponteiro para o incio da rea onde devem ser armazenados os dados lidos; tamanho = tamanho do registro lgico; nro = quantidade de registros lgicos a serem lidos; fstream = ponteiro para o arquivo; fread retorna o nmero de itens que conseguiu ler do arquivo. Funo feof - Teste de Fim de Arquivo: A funo de teste de fim de arquivo feof retorna o valor lgico verdadeiro quando o programa tenta ler o arquivo aps o ltimo byte gravado. Sintaxe:
<x> = feof (<fstream>);

onde: fstream = ponteiro para o arquivo; x = um inteiro que recebe o valor 1 se foi encontrado o fim de arquivo, seno recebe 0. Ex.:
while(!feof(arq1)) fread(&buf,sizeof(int),10,arq1);

Exemplo de um programa que grava e escreve na tela uma estrutura de nome e idade:
#include #include #include #include <conio.h> <stdio.h> <stdlib.h> <io.h>

typedef struct{ char nome[30]; int idade; } pessoa; pessoa cliente; FILE *arq1; int i, tamanho; void main(void) { clrscr(); arq1 = fopen("clientes.dat","ab+"); if (arq1==NULL) exit(1); for(i=0;i<4;i++); { printf("nome: "); fflush(stdin); gets(cliente.nome); fflush(stdin); printf("idade: "); scanf("%d",&cliente.idade); fwrite(&cliente,sizeof(cliente),1,arq1); } clrscr(); rewind(arq1);

Apostila de Linguagem de Programao II

47

while(!feof(arq1)){ fread(&cliente,sizeof(pessoa),1,arq1); if(!feof(arq1)) printf("nome: %s - %d anos\n",cliente.nome, cliente.idade); } getch();

9.4 Funes de Escrita e Gravao em Arquivos Texto


Funo fputc A funao fputc permite que se armazene um caracter (um byte) em um arquivo texto. Sintaxe:
fputc(<char>,<fstream>);

onde: char = caracter a ser gravado; fstream = ponteiro para o arquivo; Funo fgetc A funao fgetc permite que se leia um caracter (um byte) de um arquivo texto. Sintaxe:
<c> = fgetc(<fstream>);

onde: c = varivel que recebe o caracter lido; fstream = ponteiro para o arquivo; Funo fputs A funao fputs permite que se grave um string em um arquivo texto. Sintaxe:
fputs(<str>,<fstream>);

onde: str = ponteiro para o string a ser gravado (substitui o \0 por um \n no momento da gravao); fstream = ponteiro para o arquivo; Funo fgets A funao fgets permite que se leia um string inteiro de uma s vez de um arquivo texto. L todos os caracteres at encontrar um \n ou estourar o limite estabelecido nos parmetros. Sintaxe:
fgets(<str>,<tammax>,<fstream>);

onde: str = ponteiro para o string a ser lido (carrega todos os caracteres at encontrar um \n e acrescenta um \0 no fim do string). tammax = nmero mximo de caracteres que podemser lidos. fstream = ponteiro para o arquivo; Funo fprintf A funao fprintf permite a gravao formatada de dados em um arquivo texto. Os dados so armazendados no arquivo da mesma maneira que seriam jogados no dispositivo de sada padro. A sintaxe igual a da funo printf diferenciando-se apenas pela indicao do arquivo destino.

Apostila de Linguagem de Programao II

48

Sintaxe:
fprintf (<fstream>, <string de controle>, <lista de argumentos>);

funciona como o comando printf com a diferena que os caracteres so enviados para o arquivo especificado por fstream.

Funo fscanf Possui a mesma filosofia de fprintf s que para a leitura de dados. Possui sintaxe idntica a da funo scanf diferenciando-se apenas pela indicao do arquivo fonte. Sintaxe:
fscanf (<fstream>, <string de controle>, <lista de argumentos>);

Funciona como o comando scanf com a diferena que os caracteres so lidos do arquivos especficado por fstream O programa abaixo um exemplo de programa que utiliza as funes fgets, fputs, fgetc, fputc, fscanf, fprintf, para manipular um arquivo texto.
#include #include #include #include <stdio.h> <conio.h> <stdlib.h> <string.h>

FILE *arq1; char i, caracter, meu_complemento[20], frase_do_arq[80]; void main(void){ arq1 = fopen("teste.txt","w+t"); if(arq1==NULL) { printf("Nao foi possivel abrir o arquivo!"); exit(1); } strcpy(meu_complemento,"Maravilhoso!"); fprintf(arq1,"Ola Mundo %s\n",meu_complemento); fputs("Este e' o alfabeto: ",arq1); for(i=65;i<=90;i++) fputc(i,arq1); clrscr(); rewind(arq1); fscanf(arq1,"%s",frase_do_arq); printf("%s",frase_do_arq); fgets(frase_do_arq,80,arq1); printf("%s",frase_do_arq); while(!feof(arq1)) { caracter=fgetc(arq1); putchar(caracter); } getch(); }

9.4.1 Funes "fseek" , "ftell" e "rewind" As funes fseek, ftell e rewind so usadas para determinar ou modificar a localizao do marcador de posio de arquivo. A sintaxe :
fseek (ponteiro_arquivo, bytes_de_deslocamento, de_onde);

A funo fseek reinicializa o marcador de posio no arquivo apontado por por ponteiro_arquivo para o nmero de bytes_de_deslocamento a partir: do incio do arquivo (de_onde = 0) da localizao atual do marcador de posio no arquivo (de_onde = 1)

Apostila de Linguagem de Programao II

49

do final do arquivo (de_onde = 2).

A funo fseek retornar 0 se o reposicionamento for bem sucedido ou EOF se no. Para determinar a quantidade de bytes_de_deslocamento pode-se usar a funo sizeof que retorna o tamanho de uma varivel ou de uma estrutura. Exemplo:
fseek(arq1,sizeof(float),0); fseek(arq1,sizeof(clientes),1);

A funo ftell retorna a posio atual do marcador de posio no arquivo apontado por ponteiro_arquivo. Esta posio indicada por um deslocamento medido em bytes, a partir do incio do arquivo. A sintaxe :
varivel_long = ftell (ponteiro_arquivo);

A funo rewind simplesmente reinicializa para o incio do arquivo o marcador de posio no arquivo apontado por ponteiro_arquivo. A sintaxe :
rewind(ponteiro_arquivo);

9.5 Resumo de utilizao de arquivos


O primeiro passo para se trabalhar com arquivos definir quais os campos que queremos que constem nos registros e defini-los na seo das declaraes de variveis globais do programa. Exemplificando vamos criar um arquivo de clientes que contenha o cdigo, o nome e a idade. Antes do programa principal vamos incluir nossa estrutura de dados:
typedef struct { char codigo[5]; char separador; char nome[30]; int idade; } pessoa;

Pessoa o conjunto de informaes (estrutura) que contm o cdigo, o nome e a idade de cada cliente. Depois necessrio definir uma varivel para cada estrutura criada, pois somente a criao de estruturas no define nada, pois eles no tem ligao direta com o programa. Logo abaixo so declaradas as variveis referentes s estruturas criadas. Normalmente se usa uma abreviao da estrutura para denominar a varivel, ou qualquer nome que tenha alguma relao com a estrutura, mas pode-se utilizar qualquer nome.
pessoa cliente;

Cliente uma varivel associada a uma estrutura do tipo pessoa. Toda a vez que no programa quisermos fazer referncia aos registros dos clientes, vamos utilizar a varivel cliente. Antes de se utilizar os comandos para criar, abrir ou fechar o arquivo necessrio associ-lo uma estrutura que j prestabelecida (FILE) e que contm as informaes referentes ao arquivo atravs de um ponteiro.
FILE *arq1;

Para abrir ou criar um arquivo usamos o comando fopen, associando-o ao seu ponteiro
arq1 = fopen("clientes.dat","ab+");

Apostila de Linguagem de Programao II

50

Ao no especificar-se a unidade de disco na qual ser gerado o arquivo CLIENTES.DAT ele ser gerado na unidade na qual est o programa principal. Pode-se especificar uma unidade especfica, como por exemplo:
arq1 = fopen("b:\clientes.dat","ab+");

Para fechar um arquivo usa-se o comando fclose:


fclose(arq1);

No procedimento incluso devemos: 1. Abrir o arquivo em modo a+ para garantir que a escrita seja ao final do arquivo. 2. Ler cada um dos campos da estrutura. 3. Se os campos forem somente caracteres, um campo pode unir-se a outro se todos os caracteres forem preenchidos. Por isso, s vezes torna-se necessrios criar na estrutura campos separadores correspondentes a um caracter, que no lido, mas preenchido com \0 (caracter de final de string). 4. Gravar a estrutura no arquivo, atravs do comando fwrite. 5. Fechar o arquivo
void inclusao(){ arq1 = fopen("clientes.dat","ab+"); if (arq1==NULL) exit(1); clrscr(); fflush(stdin); printf("Codigo: "); gets(cliente.codigo); printf("Nome: "); gets(cliente.nome); fflush(stdin); printf("Idade: "); scanf("%d",&cliente.idade); cliente.separador='\0'; fwrite(&cliente,sizeof(cliente),1,arq1); fclose(arq1); }

Para Listar um registro devemos: 1. Ler a varivel a ser pesquisada 2. Abrir o arquivo em modo r (somente leitura) 3. Posicionar o ponteiro no incio do arquivo 4. Ficar lendo at encontrar o campo esperado, e listar o registro. 5. Se no encontrar, mostrar uma mensagem 6. Fechar o arquivo
void consultar(void){ char codaux[5]; int achou; arq1 = fopen("clientes.dat","rb+"); if (arq1==NULL) return; fflush(stdin); clrscr(); printf("Codigo a consultar: "); gets(codaux); achou=0; rewind(arq1); while(!feof(arq1)) { fread(&cliente,sizeof(pessoa),1,arq1); if(strcmp(cliente.codigo,codaux)==0) { printf("%s - %s - %d anos\n",cliente.codigo,cliente.nome, cliente.idade); achou=1; break; } }

Apostila de Linguagem de Programao II

51

if(achou==0) printf("Codigo nao encontrado!"); getch(); fclose(arq1);

Para alterar um registro ou excluir um registro (marcar com caracteres especficos), o mtodo para localiz-lo sempre o mesmo: 1. Ler a varivel a ser pesquisada 2. Abrir o arquivo em modo r+ (leitura/gravao) 3. Posicionar o ponteiro no incio do arquivo 4. Ler uma varivel a ser encorntrada 5. Ficar lendo at encontrar o campo esperado, e listar o registro. 6. Se no encontrar, mostrar uma mensagem 7. Fechar o arquivo
void alterar(void) { char codaux[5]; int achou; char campo; long int pos; arq1 = fopen("clientes.dat","rb+"); if (arq1==NULL) return; clrscr(); printf("Codigo a alterar: "); gets(codaux); achou=0; rewind(arq1); while((!feof(arq1)) && achou==0){ pos=ftell(arq1); fread(&cliente,sizeof(pessoa),1,arq1); if(strcmp(cliente.codigo,codaux)==0) achou=1; } if(achou==1) { do{ clrscr(); printf(" 1 - %s\n 2 - %s\n 3 - %d anos\n",cliente.codigo,cliente.nome, cliente.idade); printf("Campo a alterar ([9] - grava e sai): "); campo=getche(); if (campo=='1'){ fflush(stdin); printf("\n Codigo: "); gets(cliente.codigo); } if (campo=='2'){ fflush(stdin); printf("\n Nome: "); gets(cliente.nome); } if (campo=='3'){ fflush(stdin); printf("\n Idade: "); scanf("%d",&cliente.idade); } } while(campo!='9'); fseek(arq1,pos,0); fwrite(&cliente,sizeof(cliente),1,arq1);

} else {

Apostila de Linguagem de Programao II

52

printf("Codigo nao encontrado!"); } getch(); fclose(arq1);

Para listar todos os registros: 1. abrir o arquivo em modo r (somente leitura) 2. posicionar o ponteiro no incio do arquivo (rewind) 3. enquanto no chegar no final do arquivo (feof), ficar lendo (fread) um conjunto de bytes referentes a estrutura (sizeof(pessoa)), 1 vez, do arquivo arq1 4. Se no chegou no final do arquivo, mostra o registro lido 5. fecha o arquivo (fclose).
void listagem(void){ arq1 = fopen("clientes.dat","rb+"); if (arq1==NULL) return; clrscr(); rewind(arq1); while(!feof(arq1)){ fread(&cliente,sizeof(pessoa),1,arq1); if(!(feof(arq1))){ printf("%s - %s - %d anos\n",cliente.codigo,cliente.nome, cliente.idade); } } getch(); fclose(arq1); }

interessante testar se no chegou no final do arquivo, pois o C, ao ler o ltimo registro, ainda no est em EOF (final de arquivo), e sim, no ltimo byte do arquivo. A posio de EOF s atingida quando se tenta ler outro byte alm do ltimo. Se no for testada a posio de EOF para mostrar o registro lido, pode-se ter a ltima informao duplicada na tela. Exemplo de Programa Principal
void main(void) { do { clrscr(); gotoxy(10,5); printf("1 - Incluir"); gotoxy(10,6); printf("2 - Consultar"); gotoxy(10,7); printf("3 - Alterar"); gotoxy(10,8); printf("4 - Listar"); gotoxy(10,9); printf("9 - Sair"); gotoxy(10,10); printf("Escolha a opo: "); op=getche(); if(op=='1') inclusao(); if(op=='2') consultar(); if(op=='3') alterar(); if(op=='4') listagem(); } while(op!='9'); clrscr();

Apostila de Linguagem de Programao II

53

10. ALOCAO DINMICA DE MEMRIA


Quando um programa em C ou Pascal compilado, a memria do computador dividida em quatro zonas que contm o cdigo do programa, todos os dados globais, a pilha, e o heap. O heap a rea de memria livre (algumas vezes chamada de armazm livre) que manipulada com as funes de alocao dinmica malloc e free (C) e Getmem e Freemem (Pascal). Quando malloc (C) ou Getmem (Pascal) chamada, ela aloca um bloco contguo de armazenagem para o objeto especificado e ento retorna um ponteiro para o incio do bloco. A funo free (C) ou Freemem (Pascal) retorna a memria alocada previamente para o heap, permitindo que a poro da memria seja realocada. O argumento passado para malloc um inteiro no-sinalizado que representa o nmero necessrio de bytes de armazenagem. Se houver memria disponvel, malloc retornar void * que pode ser convertido para o tipo desejado de ponteiro. Um ponteiro void significa um ponteiro de tipo desconhecido ou genrico. Um ponteiro void no pode ser usado para referenciar qualquer coisa (pois ele no aponta para qualquer tipo especfico de dado), mas pode conter um ponteiro de qualquer outro tipo. Portanto podemos converter qualquer ponteiro num ponteiro void e reconverter sem qualquer perda de informao. O seguinte exemplo aloca armazenagem para um nmero varivel de valores float:
#include <stdio.h> #include <conio.h> #include <stdlib.h> float *fpt; int i, qtd; void main(void) { clrscr(); printf("Quantidade de valores: "); scanf("%d",&qtd); fpt = (float *) malloc( sizeof(float) * qtd); for (i=0;i<qtd;i++) { printf("%d valor: ",i+1); scanf("%f",&fpt[i]); } for (i=0;i<qtd;i++) { printf("%d valor: %6.2f\n",i+1,fpt[i]); } getch(); free(fpt); }

A funo malloc obtm armazenagem suficiente para tantas vezes o tamanho de um float quanto for solicitado. Cada bloco de armazenagem requisitado inteiramnte separado e distinto de todos os outros. No podemos fazer suposies sobre onde os blocos sero alocados. Os blocos so tipicamente identificados com algum tipo de informao que permite que o sistema operacional gerencie sua localizao e tamanho. Quando o bloco no mais necessrio, podemos retorn-lo para o sistema operacional por meio do seguinte comando: free( < nome_ponteiro > ) Quando precisamos de variveis com um tamanho desconhecido na compilao, devemos usar alocao dinamica de memria, no heap. Devemos porm tomar o cuidado de liberar a memria quando no precisamos mais da varivel, pois o compilador s devolve automaticamente a memria ocupada pelas variveis locais. Se no liberarmos a memria corretamente, o programa pode vir a travar.

Apostila de Linguagem de Programao II

54

A grande vantagem da utilizao de alocao dinmica que permite-se criar estruturas semelhantes a matrizes com dimenses desconhecidas no momento da compilao. Devido a uma limitao da linguagem Pascal, uma matriz ou vetor no pode ocupar mais do que 64 Kbytes de memria, portanto, quando necessitamos de uma matriz ou vetor com mais de 64 Kbytes devemos usar alocao dinmica de memria. Pode-se inclusive criar matrizes com nmero variado de colunas para cada linha, como por exemplo:
#include #include #include #include <stdio.h> <stdlib.h> <conio.h> <alloc.h>

int **matriz; int *colunas; unsigned long lin, col, i, j; void main(void) { clrscr(); printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft()); printf("Linhas: "); scanf("%d",&lin); matriz=(int **) malloc(sizeof(int *) * lin); colunas=(int *) malloc(sizeof(int) * lin); printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft()); if (matriz==NULL) { printf("Nao foi possivel alocar memoria\n"); exit(1); } for(i=0;i<lin;i++) { printf("Colunas na linha %d: ",i); scanf("%d",&col); matriz[i]=(int *) malloc(sizeof(int)*col); if(matriz[i]==NULL) { printf("Nao foi possivel alocar memoria\n"); exit(1); } colunas[i]=col; printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft()); } printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft()); for(i=0;i<lin;i++) { printf("Linha %d:\n",i); for(j=0;j<colunas[i];j++) { printf("%d Valor: ",j); scanf("%d",&matriz[i][j]); } } for(i=0;i<lin;i++) { printf("\n"); for(j=0;j<colunas[i];j++) { printf("%5d",matriz[i][j]); } } for(i=0;i<lin;i++) { free(matriz[i]); } free(matriz); free(colunas); printf("\nMemoria livre: %lu bytes\n", (unsigned long) coreleft()); getch(); }

Apostila de Linguagem de Programao II

55

10.1 Lista encadeada com alocao dinmica de memria:


Uma lista encadeada a forma ideal de armazenamento de dados quando no se sabe antecipadamente quantos itens de dados tero de ser armazenados. Ela funciona ssim: para cada item, existe tambm um ponteiro direcionado para o item de dados seguinte. A qualquer momento, pode-se acrescenta outro item de dados lista, contanto que o que o ltimo ponteiro seja atualizado a fim de apontar para o novo item de dados. Partindo-se do incio da lista, possvel percorr-la utilizando-se o ponterio de cada item, que aponta para o prximo item de dados. O tlimo ponteiro da lista geralmetne um ponteiro NULL, portando, sabemos que estamos no final da lista quando encontramos um ponteiro NULL. preciso tambm termos 3 ponteiros auxiliares, para a alocao dinmica da memria: um ponteiro que aponta para o primeiro elemento, para saber onde inicia a lista, um ponteiro que aponta para o ltimo elemento da lista, para colocarmos o valor do novo ponteiro quando inserido um elemento sem ter que percorrer a lista inteira, e um ponteiro auxiliar, que aponta para a nova rea de memria alocada. Esquematicamente, uma lista encadeada semelhante a:

dados ponteiro

dados ponteiro

dados ponteiro

dados NULL

Podemos observar no exemplo a seguir, uma lista encadeada com alocao dinmica de memria.
#include <stdio.h> #include <conio.h> #include <stdlib.h> typedef struct produto int codigo; char descr[40]; float preco; struct produto *prox; } produto; produto *prim, *ult, *aux; int cod; void ledados(produto *p, int c); void imprime(); void liberamem(); void main(void) { prim=ult=NULL; while(1) { clrscr(); printf("Codigo: "); scanf("%d",&cod); if (cod<0) break; aux=(produto *) malloc(sizeof(produto)); if (aux==NULL) { printf("Sem memoria"); exit(1); } ledados(aux,cod); if(prim==NULL) { prim=aux; ult=prim; } else { ult->prox=aux; ult=aux; } } {

Apostila de Linguagem de Programao II

56

imprime(); getch(); liberamem(); {

void ledados(produto *p, int c) float precoaux; clrscr(); p->codigo=c; fflush(stdin); printf("Codigo: %d\n",p->codigo); printf("Descricao: "); gets(p->descr); fflush(stdin); printf("Preco: "); scanf("%f",&precoaux); p->preco=precoaux; p->prox=NULL; }

void imprime() { aux=prim; while(aux!=NULL) { printf("%d - %s - %f\n",aux->codigo, aux->descr, aux->preco); aux = aux->prox; } } void liberamem() { aux=prim; while(aux!=NULL) { free(aux); aux = aux->prox; } }

O exemplo abaixo a implementao de uma lista encadeada com alocao de memria simples, sem ordenao sendo toda nova informao includa no final da lista:
#include #include #include #include #include <stdio.h> <stdlib.h> <conio.h> <alloc.h> <ctype.h>

void liberar(); void listar(); void insere(unsigned char infoaux); struct lista { unsigned char info; struct lista *elo; }; struct lista *pri, *aux, *ult, *pen; unsigned char infoaux; void main(void){ clrscr(); pri=NULL; ult=NULL; do { gotoxy(1,1); printf("Digite uma Letra: ");

Apostila de Linguagem de Programao II

57

} while ((infoaux>=65)&&(infoaux<=90)); getch(); liberar(); }

infoaux=toupper(getch()); if ((infoaux>=65)&&(infoaux<=90)) insere(infoaux); listar();

void listar() { struct lista *lult; lult=pri; gotoxy(1,10); while(lult!=NULL){ printf("%c ",lult->info); lult=lult->elo; } } void liberar() { struct lista *lult; lult=pri; gotoxy(1,10); while(lult!=NULL) { aux=lult; lult=lult->elo; free(aux); } } void insere(unsigned char infoaux) { aux=(struct lista *) malloc(sizeof(struct lista)); if (aux==NULL) { printf("Nao foi possivel alocar memoria\n"); exit(1); } if (pri==NULL) { aux->info=infoaux; aux->elo=NULL; pri=aux; ult=pri; } else { aux->info=infoaux; aux->elo=NULL; ult->elo=aux; ult=aux; } }

O exemplo abaixo a implementao de uma lista encadeada com alocao de memria com ordenao das informaes, ou seja, as informaes so inseridas na lista de forma que ela sempre est com os dados em ordem crescente:
#include <stdio.h>

Apostila de Linguagem de Programao II

58

#include #include #include #include

<stdlib.h> <conio.h> <alloc.h> <ctype.h>

void liberar(); void listar(); void insere(unsigned char infoaux); struct lista { unsigned char info; struct lista *elo; }; struct lista *pri, *aux, *ult, *pen; unsigned char infoaux; void main(void) { clrscr(); pri=NULL; do

{ gotoxy(1,1); printf("Digite uma Letra: "); infoaux=toupper(getch()); if ((infoaux>=65)&&(infoaux<=90)) insere(infoaux); listar(); } while ((infoaux>=65)&&(infoaux<=90)); getch(); liberar(); } void listar() { struct lista *lult; lult=pri; gotoxy(1,10); while(lult!=NULL) { printf("%c ",lult->info); lult=lult->elo; } } void liberar() { struct lista *lult; lult=pri; gotoxy(1,10); while(lult!=NULL) { aux=lult; lult=lult->elo; free(aux); } } void insere(unsigned char infoaux) { int inseri;

Apostila de Linguagem de Programao II

59

aux=(struct lista *) malloc(sizeof(struct lista)); if (aux==NULL) { printf("Nao foi possivel alocar memoria\n"); exit(1); } if (pri==NULL) { aux->info=infoaux; aux->elo=NULL; pri=aux; } else { if(pri->info > infoaux) { aux->info=infoaux; aux->elo=pri; pri=aux; } else { if(pri->elo == NULL) { aux->info=infoaux; aux->elo=NULL; pri->elo=aux; } else { inseri=0; pen=pri; ult=pri; while(inseri == 0 && ult->elo != NULL) { if (ult->elo != NULL) { pen=ult; ult=ult->elo; } if (ult->info > infoaux) { aux->info=infoaux; aux->elo=ult; pen->elo=aux; inseri=1; } } if (inseri==0) { aux->info=infoaux; aux->elo =NULL; ult->elo =aux; } } } } }

Apostila de Linguagem de Programao II

60

BIBLIOGRAFIA GUEZZI, Carlo & JAZAYERI, Mehdi. Conceitos de Linguagem de Programao. Rio de Janeiro, Ed. Campus. 1985. KELLY-BOOTLE, Stan. Dominando o Turbo C. Rio de Janeiro, Ed. Cincia Moderna. 1989. KERNIGHAM, Brian W. & RITCHIE, Dennis M. C: A Linguagem de Programao. Rio de Janeiro, Ed. Campus. 1986. LONGO, Maurcio B.; SMITH Jr., Ronaldo & POLISTCHUCK, Daniel. Delphi 3 Total. Rio de Janeiro, Brasport Livros e Multimdia Ltda. 1997. MECLER, Ian & MAIA, Luiz Paulo. Programao e Lgica com Turbo Pascal. Rio de Janeiro, Ed. Campus. 1989. PALMER, Scott D. Guia do Programador - Turbo Pascal for Windows. Rio de Janeiro, Editora Cincia Moderna. 1992. PAPPAS, Chris H. & MURRAY, Wiliam H. Borland C++. So Paulo, Makron Books. 1995. PREUSS, Evandro, Apostila de Linguagem de Programao. Frederico Westphalen, 2003. http://www.uri.br/~preuss RINALDI, Roberto. Turbo Pascal 7.0: Comandos e Funes. So Paulo, rica. 1993. SCHILDT, Herbert. Linguagem C: Guia Prtico e Interativo. So Paulo, McGraw-Hill. 1989. WIENER, Richard S. Turbo C Passo a Passo. Rio de Janeiro, Ed. Campus. 1991

Potrebbero piacerti anche