Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
DEPARTAMENTO
DE
DO
ALTO URUGUAI
Linguagem de Programao II
Linguagem C
1 Semestre/2004
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
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
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.
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.
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 */
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...
3. DADOS
Nessa sesso sero apresentados as variveis e operaes utilizadas na linguagem C.
Na linguagem C, o restante dos comandos so todos funes (da biblioteca padro ou no). Todas as palavras reservadas devem ser escritas em minsculo.
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.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.
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.
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...
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
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.
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;
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;
11
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)
+=
> > > >
*=
/=
%=
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;
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.
OPERAO e ou no ou exclusivo shift para direita (diviso por 2) shift para esquerda (multiplicao por 2)
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:
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).
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.
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:
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.
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);
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.
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
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.
17
Exemplo:
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(); }
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>; }
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){
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"); }
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"); } }
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.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--;
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.
22
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);
...
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.
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
25
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);
26
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.
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
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)
27
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]
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.
28
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: ");
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."); }
30
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
strncpy strnicm p
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.
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.
33
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]); }
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]); } }
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
FFF4
FFF4
void main(void){ clrscr(); int num = 55, valor; int *p; p = # 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 = # 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
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(); }
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(); }
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);
36
37
int_dado 5
[1112]
int_ptr1 1112
[2368]
int_ptr2 2368
[3219]
int_ptr3 3219
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.
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);
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
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); }
39
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); }
40
void imprime(struct cadastro pessoas){ clrscr(); printf(%s mora na rua %s, na cidade de %s, pessoas.nome, pessoas.endereco, pessoas.cidade); }
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); } }
struct cadastro { char nome[30]; char endereco[50]; char cidade[20]; struct data dnasc; }; void main(void) { int i; cadastro cliente[5];
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); } }
Ento poderemos declarar um ponteiro denominado meu_ponteiro para meus_dados como este:
struct grande_estrutura_dados *meu_ponteiro;
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;
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.
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.
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);
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.
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: 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
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);
47
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.
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)
49
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);
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+");
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+");
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; } }
51
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 {
52
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();
53
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.
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(); }
55
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; } } {
56
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: ");
57
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>
58
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;
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; } } } } }
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