Apostila de LINGUAGEM
C
(Com Exercícios Adicionais)
Prof. Antônio Carlos GuimarãesSalgado Laboratório Nacional de Computação Científica – LNCC & Prof Pr of.. Re Regi gina nald ldo o S. Fi Figu guei eire redo do – M. M.S. S.C. C. – I.M.E.
Março.2010
SUMÁRIO PARTE I – A LINGUAGEM C 1 1.1 1.2 1.3
Introdução Linguagem C .............................................................................................. Características & histórico ............................................................................................. Características de um programa C ................................................................................ Formato de um programa em C .....................................................................................
04 04 04 04
2
Identificadores .................................................................................................................
05
3 3.1 3.2
Tipos de Dados Para Variáveis e Funções ...................................................................... Standard (já definidos na linguagem) ......................................................................... Modificadores de tipo .................................................................................................
05 05 05
4 4.1 4.2 4.3 4.4 4.4.1 4.4.2 4.4.3 4.4.4
Declaração de variáveis .................................................................................................... Variáveis locais ........................................................................................................... Parâmetros formais ...................................................................................................... Variáveis globais ......................................................................................................... Modificadores de classe de armazenamento ............................................................... Variáveis automáticas – auto – modificadores de de classe de armazenamento armazenamento ........... ........... Variáveis externas – extern – modificadores de classe de armazenamento ............... Variáveis estáticas – statics ........................................................................................ Variável register .........................................................................................................
06 06 07 07 07 07 08 08 08
5 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10
Operadores ........................................................................................................................ Aritméticos .................................................................................................................. Lógicos ou Booleanos ................................................................................................. Relacionais .................................................................................................................. Entre bits ..................................................................................................................... Outros operadores ....................................................................................................... Precedência ................................................................................................................. Pré-processador e diretivas ......................................................................................... Diretiva #define ......................................................................................................... Diretiva #include ........................................................................................................
namespace, using namespace, comandos cin e cout do C++ .......................
08 08 09 09 09 09 09 10 10 10 11
6 6.1 6.2
Entrada e saída de dados pela console – funções printf e scanf .................................... printf ........................................................................................................................... scanf ............................................................................................................................
12 12 12
7 7.1 7.2 7.3
Instruções de controle ....................................................................................................... O comando if ............................................................................................................... O operador ? (substitui o if) ........................................................................................ O comando switch ....................................................................................................... Exercícios de fixação ........................................................................................ O comando for ............................................................................................................ O comando while ........................................................................................................ O comando do { ... } while .......................................................................................... O comando continue ................................................................................................... O comando break ........................................................................................................ O comando goto< label> ............................................................................................. Exercícios de fixação .......................................................................................
13 13 14 14 14 15 15 16 16 17 17 19
Arrays unidimensionais – Vetores ...................................................................................
20
7.4 7.5 7.6 7.7 7.8 7.9
8
2
Exercícios de fixação ........................................................................................ Arrays unidimensionais de caracteres – Strings Strings ................................................................ Funções getchar, putchar, getchar e gets ...................................................... Arrays bidimensionais – Matrizes ................................................................................... Exercícios de fixação ........................................................................................
21 22 22 24 26
10
Funções ..............................................................................................................................
27
11 11.1 11.2 11.3
O tipo Pointer – Ponteiro .................................................................................................. Definição ..................................................................................................................... Iniciação de ponteiros na definição ............................................................................. Passagem de parâmetros por endereço (por referência) ..............................................
28 28 29 29
12
A relação entre ponteiros e arrays ...................................................................................
30
13 13.1 13.2
Ponteiros e arrays bidimensionais ................................................................................... Arrays tridimensionais ................................................................................................ Arrays de ponteiros – ragged arrays ..........................................................................
32 34 35
14
Alocação dinâmica de memória .......................................................................................... A função malloc .......................................................................................................... Vetores gerados dinamicamente ....................................................................... A função calloc ........................................................................................................... A função realloc ......................................................................................................... A função free ...............................................................................................................
36 36 37 37 38 38
15
Definição de novos tipos ...................................................................................................
39
16 16.1 16.2 16.3 16.4 16.5
Estruturas – structs .......................................................................................................... Iniciação de estruturas ................................................................................................. Campos de bits ........................................................................................................... Uniões ......................................................................................................................... Ponteiros para estruturas ............................................................................................. Ponteiro para percorrer array de ponteiros .................................................................
39 41 41 41 43 44
17
Ponteiros para funções .....................................................................................................
45
18
Tipos enumerados .............................................................................................................
46
19 19.1 19.1.1 19.1.2 19.2 19.3
Arquivos ............................................................................................................................. Funções para Abertura e fechamento de arquivos ................................................. Função para abertura de arquivos ..................................................................... Função para afechamento de arquivos .............................................................. Principais funções para leitura e gravação seqüenciais ................. ....................... ............ ............ ............ ...... Principais funções para leitura e gravação direta direta (tipos texto e binário) ............. .............
47 47 47 49 49 50
Referências Bibliográficas .............................................................................................. Exercícios Adicionais ........................................................................................................
55 56
8.1 9
A Linguagem C 1. Introd Introdução ução a ling linguage uagem mC 3
Características & Histórico • • • • • • • • • • •
linguagem de médio nível; linguagem estruturada; versátil (aplicação em várias áreas); portável; código eficiente; compilação condicional; compilação separada (funções em vários arquivos); linguagem para o programador. BCPL ⇒ B ⇒ C ⇒ C++ C - 1971 - Kernighan e Ritchie (K & R) C ANSI (American National Standards Institute) - 1989
Características de um programa • • • • •
Um programa programa em C é composto por pelo menos uma função, a função "main"; Todo programa programa em C começa a sua execução a partir da função "main"; Normalmente, um programa em C é uma coleção de funções de pequeno tamanho; Toda função tem um tipo; Palavras reservadas e funções da biblioteca do C são sempre escritas com letras minúsculas.
1.3. Formato de um programa em C "definições" função_1 função_2 ... função_n funcão_main / A ordem ordem das funções dentro dentro de um programa programa pode ser qualquer qualquer •
Exemplo de um programa
#include
// Instrução para o pré-processador
void main ( ) { int i; i = 10; printf printf ("i = %d\n", %d\n", i); }
// // // // // //
Início da função main Início de bloco Define “i” co como uma variável do tipo inteiro Iinicia “i” Chama função de impressão impressão Fim de bloco
// Toda Toda instru instrução ção termin terminaa por ” ; “ e o protótipo de printf está em stdio.h (standard IO )
2. Iden Identi tific ficad ador ores es São usados em nomes de funções e variáveis. A maioria dos compiladores reconhece reconhece 31 caracteres tanto para variáveis quanto para funções, e: • •
Devem começar por letra ou '_'; Normalmente se usam letras minúsculas; 4
• •
Não podem ser iguais às palavras reservadas; Minúsculas são compredidas como diferentes de maiúsculas (e.g.: ABC ≠ Abc ≠ ABc ≠ abc).
3. Tipos de de Dados Dados para Variáv Variáveis eis e Funções Funções 3.1. 3.1. Stan Standa dard rd (já (já defin definid idos os na na lingu linguage agem) m) caracter inteiro inteiro duplo real real duplo nada
char int long int float double void
(1 caractere) (2 bytes) (4 bytes) (4 bytes) (8 bytes) (0 bytes)
O tipo inteiro possui o tamanho da palavra p alavra da CPU.
Tipo Char int long int Float Doublé Void
Tamanho em Bits 8 16 32 32 64 0
Faixa 0 a 255 -32768 a 32767 –2,147,483,648 a 2,147,483,647 6 dígitos 12 dígitos Sem valor
3.2. 3.2. Modi Modifi fica cado dore ress de tipo tipo Alteram o significado do tipo standard. • • • •
signed (com sinal) unsigned (sem sinal) long (passa inteiro de 2 bytes para 4 bytes) short (passa inteiro de 4 bytes para 2 bytes)
Se tipo int: long int = long short int = int
⇒
Exem Exempl plos os:: sign signed ed char char unsigned int
⇒
⇒
⇒
4 bytes 2 bytes 128 a 127 0 a 65535 −
4. Declaração Declaração de Variáv Variáveis eis Variáveis devem ser declaradas antes de serem usadas. Formato: Formato: ; variáveis>; Exem Exempl plos os:: int int float double char
a, b, c; soma; somatorio, raiz_quadrada; sim, nao;
As variáveis podem ser definidas dentro de qualquer bloco: { 5
}
4.1 4.1.
int x, y; < bloco de comandos >;
Variá ariávveis eis lo locais cais
São as declaradas dentro de blocos e só são reconhecidas dentro do bloco de declaração.
// Exemplo: #include void main ( ) { int i = 2, j; j = 2 * i; printf ("O dobro de %d = %d\n", i, j); } /* No exemplo acima, “ i “ e “ j “ são variáveis locais da função função “main” . */
// Exemplo: void f1 ( ) { int x; x = 5; ... if (a > 10) { int x, y; x = 20; y = 40; ... } } // No exe exemp mplo lo,, a vari variáv ável el x tem o valor 5 quando sair do bloco mais interno.
4.2. 4.2. Parâme Parâmetro tross forma formais is – os os parâm parâmetr etros os das das funçõ funções. es. Quando parâmetros são passados por valor a função só recebe cópia do conteúdo da variável. Exemplo:int soma (int a, int b) { return (a + b); } No exemplo, a e b são parâmetros formais e a função soma poderia ser chamadadas seguintes formas: ou x = soma (a, b); j = soma (2, 3);
4.3. 4.3. Variá ariávveis eis glob globai aiss São reconhecidas por todas as funções de um programa p rograma ou de um arquivo. // Exemplo: #include int cont; 6
void f ( void ); void main ( ) { cont = 100; printf("cont em main = %d\n", cont); cont); cont = cont + 1; f ( ); } void f ( ) { printf("cont em f = %d\n", cont); }
4.4. 4.4. Modific Modificado adores res de class classee de de armaz armazena enamen mento to Indicam como as variáveis devem ser armazenadas. Exemplo de mapa da memória de um programa em C em um equipamento genérico: Stack
Heap Variáveis Estáticas e Globais Área de Código
4.4.1. 4.4.1. Variáveis Variáveis automáticas automáticas – auto – são as as variávei variáveiss definidas definidas normalm normalmente ente.. Exe Exemplo: plo:in intt x; x; <=> <=> auto auto int int x; x; A palavra auto não é necessária.
4.4.2. Variáveis externas – extern – são variáveis globais definidas em arquivos diferentes. // Exemplo: Exemplo: arquivo arquivo 1: void main ( ) { int x, y; y = 30; x = 10; f ( ); ... } // arquivo 2: extern int x, y; void f ( ) { ... printf ("%d %d\n", x, y); ... } 7
4.4.3. 4.4.3. Variáveis Variáveis estáticas estáticas - static static A variável não perde o seu valor dentro da função ou arquivo. Este tipo de variável é mais empregado para definição de strings . Quando uma função é definida como static, ela só pode ser ativada por uma função que esteja no mesmo arquivo.
4.4. 4.4.44
Variá riáveis veis regi regisster ter
A variável é colocada em um dos registradores da CPU e, por isso, i sso, dve ser bem escolhida Ex.: Ex.: regi regist ster er int int i,i, j; Este tipo de variável é mais usada em casos nos quais a velocidade é importante, como, por exemplo, em variáveis que controlam laços.
5. Oper Operad ador ores es Um operador operador é um caracter ou grupo de caracteres que causará uma manipulação matemática ou lógica. Em C, os operadores podem ser aritméticos, relacionais e lógicos e entre bits.
5.1. Aritméticos + ≡ −
≡
* / %
≡ ≡
+= −= *= /=
−−
++
adição ⇒ subtração (e menos unário) ⇒ multiplicação ⇒ divisão ⇒ resto divisão ⇒ decremento ⇒ incremento ⇒
5.2. 5.2. Lógi Lógico coss ou bol bolea ean nos && ⇒ e | | ⇒ ou ! ⇒ não
5.3. Relacionais > ⇒ < ⇒ == ⇒ != ⇒ >= ⇒ <= ⇒
maior menor igual diferente maior ou igual menor ou igual
5.4. Entre bits & ⇒ ⇒ | ^ ⇒ ~ ⇒ >> ⇒ << ⇒
e ou ou exclusivo complemento (NOT) deslocamento para direita deslocamento para esquerda
5.5 5.5. Outr Outroos ope opera rad dores ores * ⇒ retorna o valor contido em um endereço 8
& sizeof ? , .
⇒
−>
⇒
(type)
⇒
retorna o endereço endereço de uma variável retorna o tamanho de uma variável ou tipo avalia expressão verdadeira verdadeira equivalente a "faça isto e isto e isto ..." membro de estrutura ou união ponteiro para membro de estrutura ou união cast (altera tipo do dado)
⇒ ⇒ ⇒ ⇒
5.6. 5.6. Prece Precedê dênc ncia ia (da (da mai maior or para para a men menor or)) ( )[ ! * + << < == & ^ | && || ? = ,
] −> ~ /
++ %
−−
( type ) * &
sizeof
−
>> <= > !=
+=
>=
=
−
* =/ =
5.7. 5.7. PréPré-pr proce ocess ssad ador or e dire direti tiva vass O pré-processador é um programa que age antes do compilador da linguagem C, aumentando sua capacidade e auxiliando a portabilidade. Ele é comandado por diretivas (que iniciam sempre pelo sinal #). As diretivas só valem no arquivo onde estão definidas ou arquivos incluídos abaixo abai xo destas diretivas
5.8
# define
Serve para definir uma constante simbólica. Por exemplo: #define TRUE 1 #define FALSE 0 #define MENS_ERRO "Erro. Divisão por zero.\n" #define MAX_TAM 100 As constantes assim definidas podem ser usadas para atribuir valores a variáveis, passadas como parâmetros e para comparações dentro do programa. Ex.: int erro; ... erro = FALSE; if (a == 0) flag = TRUE; if (erro) printf (MENS_ERRO); (MENS_ERRO); Outra finalidade do #define é criar macro funções. Por exemplo: então → se: a = MIN(x, 3); # define MIN(a, b) ((a) < (b) ? (a) : (b))
#define st streq (x, y) (strc trcmp( mp((x), x), (y (y)) == == 0) 0) /* igu iguais ais */ */ #def #defin inee str strlt( lt(x, x, y) y) (st (strc rcmp( mp((x) (x),, (y)) (y)) < 0) /* x < y */ 9
⇒
a = ((x) < (3) ? (x) : (3));
#def #defin inee str strgt gt (x, y) (str (strcm cmp( p((x (x)), (y (y)) > 0) 0)
/* x > y */
Para que se possa reutilizar uma constante devemos devemos torná-la antes indefinida, usando a diretiva #undef a seguir redefini-la novamente usando outro #define. Por exemplo: a) # define NOME "teste" ... # undef NOME # define NOME "teste" b) #define TAM 100 #define COMP 100 char array [ TAM ][ COMP ] #undef COMP #define COMP 200 char arrayb [TAM][COMP] [TAM][COMP]
5.9
# include
Permite incluir o conteúdo de um arquivo no programa. Exemplos: #include // Procura Procura stdio.h stdio.h no no diretório diretório de arquivo arquivoss header header // Procu Procura ra stdio. stdio.hh no diretó diretório rio corre corrente nte #include "stdio.h" // Procu Procura ra auxi auxiliar liar.h .h no no drive drive b #include "b:auxiliar.h" Esta última forma deve ser evitada, pois gera dependência do sistema operacional.
O comando #include é usada para incluir o acesso a biblioteca padrão de entrada e saída de dados do C++. A é uma biblioteca usada para entrada e saída de dados. Ela fornece o objeto std::cout, que serve para enviar uma mensagem para a tela e utiliza o operador <<, que indica: envie estes caracteres para saída (cout = C out). A fornece também o objeto std::cin, que é usado para entrada de dados. Observe Observe o uso do operador >> que indica: armazene a entrada do usuário neste objeto.
5.1 5.10 name namesp spac acee O que é um namespace ? Como o próprio nome diz, signifca espaço para nomes . Quando se monta programas utilizando bibliotecas externas, podem ocorrer duplicações de nomes, isto é, um objeto defnido em uma bibliotecas tem o mesmo nome de um objeto defnido por você. Por exemplo: você criou as funções min ( ) e max ( ), que retornam retornam o menor e maior valor valor de um vetor. Mas a STL – biblioteca biblioteca padrão padrão para tratamento de vetores vetores em C++ já tem estas estas funções funções e , por isso, o compilador não “saberá” que função min( ) e max ( ) você quer chamar. Solucionar o problema da duplicação de nomes pode ser complexo, pois se estes nomes pertencerem a bibliotecas externas, você precisaria contatar os desenvolvedores delas para resolver os confitos, ou renomear seus objetos e funções. O namespace veio para resolver resolver este problema. Para usar os objetos standart de C++ é preciso incluir a palavra std e a seguir o operador de resolução de escopo, isto é: std::nomeObjeto; 10
std::cout << “ Entre com x : “; // cout = saíd saídaa de de dado dadoss std::cin >> x ; // cin = entr entrad adaa de dado dadoss Obs.:os comandos cin e cout devem devem ser utilizados somente em programação ambientadas em C++ 5.11 using namespace std Mas é possível possível utilizr os objetos standarts de C++ diretamente, isto é, sem o uso de std::. Para tal basta colocar a declaração using namespace std no início do programa.
// Exemplo: Declara que vai usar os objetos standart de C++ … using namespace std; int x = 3 ; cout cout < < “ Entr Entree com com x : “; “; cin > > x ;
6. Entrada e Saída Saída de Dados Pela Pela Console – Funções printf e scanf Ao contrário de outras linguagens, no C as operações de leitura e impressão, tanto na tela quanto em arquivos, é totalmente feita por funções. Os protótipos destas funções se encontram no arquivo stdio.h, o qual deve sempre ser incluído quando forem usadas funções de IO (entrada e saída).
6.1.
printf
Principal função de impressão no vídeo e retorna o número de caracteres impressos. Formato: int printf (formato, argumentos);
Obs1.: Em C, o valor de retorno de uma função pode ser ignorado. Obs2.: Em C, as funções podem ter um número variável de parâmetros. Ex.: printf (" \n FIM \n" ) ; Principais formatos de impressão: • %d ⇒ inteiro • ⇒ %c caracter • %f ⇒ float • %ld ⇒ long int • %lf ⇒ double • %s ⇒ string • %e ⇒ notação científica // A saída pode ser formatada através do tamanho do campo: %3d ⇒ inteiro com 3 dígitos. • %7.2f ⇒ float com dois dígitos após o ponto decimal. •
6.2. scanf Principal função de leitura do teclado. Formato: int scanf (formato, parâmetros); Retorna o número de variáveis lidas corretamente ou EOF em caso de erro grave. 11
Principais formatos: %d – inteiro %c – caracter %f – float %ld – long int %lf – double %s – string Para a função scanf , o branco é considerado delimitador. Por exemplo, scanf ("%d %d", &a, &a, &b); &b); mostrará 1 3 ou 1 3 (depende (depende dos espaços entre os %d). Já scanf ("%d , %d", &a, &b); mostrará 1 , 3 (um, vírgula e três).
// Ex.: Ler dois números e imprimir a soma. # include void main ( ) { int a, b, c; printf("Entre 2 numeros: "); scanf("%d %d", &a, &b); c = a + b; printf("soma = %d\n", c); /* ou poderia ser printf("soma = %d\n", a + b); */ } 7. Instuç Instuções ões de control controlee 7.1. 7.1.
if { } ; if { … } else else { … } ; if { … } els elsee { if { … }} ; etc etc …
// Exemplo 1 if ( teste ) < um só comando; comando; > // Exemplo 2 if ( teste ) { < bloco de comandos; > } else { bloco de comandos; } // Exemplo 4: ler 2 números e indicar o maior #include void main ( ) { int a, b; printf ("Entre 2 numeros: "); scanf ("%d %d", &a, &b); if (a == b) /* todo teste de igualdade utiliza == */ printf ("Sao iguais\n"); else if (a > b) printf ("O primeiro é maior\n"); else printf ("O segundo é maior\n"); } 12
// Exemplo 5: ler uma série de números reais e indicar o maior e o menor. #include void main ( ) { float min, max, x; printf ("Entre os numeros:\n"); scanf ("%f", &x); min min = max max = x; /* atri atribu buiç ição ão múlt múltip ipla la */ while (scanf("%f", &x) == 1) if (min > x) min = x; else if (max < x) max = x; printf (" \n O maior é: %f\n", max); printf (" \n O menor é: %f\n", min); } 7.2. 7.2. O oper operad ador or ? (sub (subst stit itui ui o if ) É uma outra forma de utilização do comando if (útil para pequenos comandos comandos do tipo if). if (a == 10) { b = 20; } else { b = 30; }
b = (a == 10)
? 20 : 30;
7.3. O comando switch – substitui grandes if's. switch (exp) // A expressão exp deve fornecer um resultado inteiro. { case cte 1: bloco1; // cte = constante valor ou caractere (entre aspas simples) break ; case cte 2: bloco2; break ; case cte 3: bloco3; break ; ... ... case cte n: bloco bloco n; n; break ; default : bloco default ; brea breakk; /* não é nece ecessár ssário io break aqui */ }
Exercícios de Fixação 1)
Implem Implemen ente te um pro progra grama ma que que receb recebaa 3 (três) (três) núme números ros inte inteiro iros, s, atrav através és do teclad teclado, o, e visu visualiz alizee qual qual o maior e qual o menor deles.
2)
Implem Implemen ente te um pro progra grama ma que que receb recebaa 4 (quatr (quatro) o) númer números os intei inteiros ros,, através através do do teclad teclado, o, e que que,, após, após, os visualize em ordem decrescente.
3)
Implem Implemen ente te um pro progra grama ma que que receb recebaa um númer númeroo inteir inteiro, o, atravé atravéss do tecl teclado ado,, perten pertencen cente te ao inter intervalo valo [1000,1010.000[, e que, após, determine e visualize: (i) seus dígitos individualmente; (ii) denomine por extenso o valor de cada dígito; e (iii) a soma dos dígitos pares do número informado. 13
4)
Implem Implemen ente te um pro progra grama ma que que receb recebaa 3 (três) (três) núme números ros inte inteiro iros, s, atrav através és do teclad teclado, o, e ver verifi ifique que se se eles eles podem formar um triângulo eqüilátero, um triângulo retângulo, ou se não permitem a formação de um triângulo. Obs.: Relação Triangular: cada lado de um um triângulo tem de ser menor que a soma dos dos outros dois dois lados ;
7.4. for ( . . . ) { . . . } Formato: for (inicial (inicializaç ização; ão; condição condição;; increme incremento nto)) // Todos os campos do for são opcionais { < bloco de comandos; > }
// Exemplos: Imprimir os números de 1 a 10 #include void main ( ) { int i; for for (i = 1; 1; i <= 10; 10; i++) i++) prin printf tf ("% ("%d\ d\n" n",, i); i); } #include void main( ) { int i = 1; for for ( ; i <= 10 10;; ) }
prin printf( tf("% "%d\ d\n" n",, i++) i++);;
7.5. while while (condição) { < bloco de comandos ; > } // Executa o bloco enquanto enquanto a condição for verdadeira verdadeira (em C, verdadeiro verdadeiro é o que não for zero). zero).
Formato:
//Exemplo: Seja fazer um programa que imprima a soma dos números de 1 a 5 com um laço while. // Solução 1: #include void main( ) { int i = 1, soma = 0; whil wh ilee (i (i <= <= 5) 5) soma soma += i++; i++; printf ("\nSoma = %d\n", soma); } // Solução 2: #include void main ( ){ int i = 1, soma = 0; whil wh ilee (i (i <= <= 5) 5) soma soma += i++; i++; printf ("\nSoma = %d\n", soma); } Obs. Ob s.:: i ++; ++; ⇔ ++ i; se a = 1: para b = ++ a; ⇒ b = 2 e a = 2 para b = a ++; ⇒ b = 1 e a = 2 14
var = var op exp; x = x + 5; x = x / (a + b);
⇔
var op = exp; x + = 5; x / = a + b;
7.6. do while Formato: do
{
< bloco de comandos; >:
} while (condição);
Repete o bloco de comandos enquanto a condição for verdadeira.
// Exemplo: Imprimir os números de 1 a 10 #include void main ( ) { int i = 1; do prin printf tf ("% ("%d\n", \n", i++ i++ );); while hile (i <= 10); 0); } // Exemplo: Calcular o fatorial de um número lido usando for. // Solução 1: #include void main ( ) { int n, i, fator = 1; printf ("Ent ("Entre re o numero: numero: "); "); scanf ("%d ("%d", ", &n); for (i = 1; i <= n; i++) fator *= i; printf (" \n Fatorial de %d = %d \n", n, n, fator ) ; } // Solução 2: #include void main ( ) { int n, i, fat; printf ("Ent ("Entre re o numero: numero: "); "); scanf ("%d ("%d", ", &n); i = n; for (fat = 1; n > 1; n– –) fat *= n; printf( " \n Fatorial de %d = %d \n", i, fat ) ; } continue Continua com o próximo incremento no for ignorando as instruções restantes dentro do bloco do for. ... for (i = 0; i < 10; i++) { if (i == 0) cont contin inue ue;; /* evi evita ta div divis isão ão por por zer zeroo */ */ printf("%f\n", (float) 10 / i); } 15
7.8. break Interrompe a execução de um for, while, do ... while ou switch. O fluxo de execução do programa é desviado para primeira instrução fora do bloco que possui o break . Ex.: while (1) /* loop infinito */ { scanf("%d" , &a); if (a != 0)processa ( ); else break; }
goto label Desvia o fluxo de execução do programa para um label em outro outro ponto do programa. goto Label_1; processa ( ); Label_1: ... // Para label sem instruções deve-se usar um “;” no final: Erro_Fatal: ;
// Exemplo: Fazer um programa que simule uma calculadora, com as quatro operações, teste // a divisão por zero e sinal inválido. # define FALSE FALSE 0 /* definição de constantes */ # define TRUE 1 # include void main ( ) { float v1, v2, res; char op; int erro = FALSE; FALSE; /* usa int como variável variável lógica */
}
printf ("Entre sua expressão:\n"); scanf ("%f ("%f %c %f", &v1, &v1, &op, &op, &v2); &v2); /* le a expressão expressão */ switch ( op ) { case case '+' '+' : res = v1 v1 + v2; bre break; ak; case '−' : res = v1 −v2: break; case case '*' : res = v1 * v2; bre break; ak; case case '/' '/' : if (v2 (v2 == 0.0) 0.0) { prin printf tf (" \n \n Er Erro: ro: Div Divis isão ão po porr ze zero\n o\n"); "); erro = TRUE; } else res = v1 / v2; break; defa defaul ult: t: erro erro = TRU TRUE; E; printf (" \n Sinal inválido i nválido \n " ) ; break; } if (!erro) // Não precisa fazer erro == TRUE printf ("\nO resultado é: %10.4f\n", res); 16
// Exemplo: Fazer um programa que leia um valor n e leia e imprima o quadrado de n números. #include void main ( ) { float x; int n; printf ("\n Número de valores a serem lidos: "); scanf ("%d", &n);
} /*
*/
while (n ––); { printf(" \nValor: "); scanf (" %f ", &x); printf (" \n Quadrado de %f = %f\n", x, x * x ) ; }
Obs.: Outras funções de entrada e saída de dados int getchar ( void );// Erro = EOF int int putc putcha harr ( int int ); ); // Err Erroo = EOF; EOF; OK = car carac acte tere re impr impres esso so..
Exercícios de Fixação 17
A seguir são apresentados vários exercícios. Quando algum deles necessitar utilizar comandos de repetição, resolva-os: (a) utilizando somente o comando do { ... } while ; (b) utilizando somente o comando while{ . . . } ; e (c) utilizando somente o comando for { . . . } . 1)
Implemente um programa que receba, através do teclado, um número natural, sem o zero, menor que 1001 (mil e um), e que, após, visualize a soma de todos os números ímpares naturais até o número digitado.
2)
Implemente um programa que receba, através do teclado, um número natural, sem o zero, menor que 501 (quinhentos e um), e que, após, visualize todos os números pares múltiplos de 3 (três) entre 1 e o número digitado. Implemente um programa que receba 3 (três) números inteiros, inteiros, através do teclado, cujos significados são, respectivamente: o primeiro termo de uma Progressão Progressão Aritmética – P. A. ; a razão desta P.A.; e sua quantidade de termos. Após, o programa deverá determinar e visualizar a soma dos termos pares da P.A. supracitada.
3)
4)
5)
Implemente um programa que calcule e visualize a soma dos 15 (quinze) primeiros termos da Progressão Geométrica 3, 9, 27, ... . É sabido que a série de Fibonacci é: 1 1 2 3 5 8 13 . . . , que pode ser definida assim: a1 = 1 ; a 2 = 1 ; e an = (an – 1) + (an – 2) para n ≥ 3 2.1) Implemente Implemente um um programa programa que visuali visualize ze um certo certo termo da da série de Fibonacci Fibonacci cuja posição posição na série deve ser informada através do teclado e deve pertencer ao intervalo [ 0 , 20 ]. 2.2) 2.2) Imple Implemen mente te um progr programa ama que que visua visualize lize a soma soma dos dos N primeiros termos da série de Fibonacci, sendo N informado através do teclado e devendo pertencer ao intervalo [1, 25 ]. 2.3) Implemente Implemente um um programa programa que exter exteriorize iorize todos todos os quadrad quadrados os perfeitos perfeitos pertence pertencentes ntes aos 25 primeiros termos da série de Fibonacci.
6)
Imple Implemen mente te um um progr programa ama que que receba receba dois dois número númeross intei inteiros ros,, atrav através és do do tecl teclado ado,, maior maiores es que que 0 (zer (zero) o) e menores que 1000 (mil), e visualize todos os cubos perfeitos compreendidos entre eles, inclusive.
7) Implemente um programa que receba, através do teclado, um número inteiro maior que – 1 (menos um) e menor que 6(seis), e que, após, visualize seu fatorial.
8. Arryas unidimensionais (vetores) numéricos Definição de vetores unidimensionais:
[]; 18
Ex.: int vet[5];
⇒
define vet como um vetor inteiro de 5 posições
A posição do primeiro elemento é vet [ 0 ] e do último vet [ 4 ]. Exemplos de acesso: int vet [ 5 ]; vet[ 0 ] = 10; vet[ 1 ] = 20; vet[ 2 ] = 40; for (i = 0 ; i < 5; i++ ) vet [ i ] = 0;
vet // Zera o vetor vet
Iniciação na definição: •
•
Para vetor local: static int vet[ ] = {1, 3, 5}; static float vet[10]; static static int vet[5 vet[5]] = {1, {1, 2, 3};
// assume que o vetor vet possui 3 elementos // assume vet com 10 elementos, que são iniciados com 0. // assume assume vet com 5 elementos; elementos; o 4º e o 5º são iniciados com 0.
Para vetor global: int vet[ vet[ ] = {10 {10,, 20, 20, 40, 50}; 50}; // assume assume vet tem 4 elementos
Quando um vetor extern ou static for iniciado sem dimensão, ela será igual ao número de valores valores da iniciação. Caso seja fornecida a dimensão e faltem elementos na iniciação, iniciaç ão, os elementos não iniciados valem zero.
// Exemplo: Fazer uma função que retorne o maior número de um vetor double. # include double doub le maxval maxval (double (double [ ]],, int); void levet (double [ ], int); void main ( ) { double vet [ 100 ]; int i, n; printf printf (" (" Nú Númer meroo ddee elemen elementos tos do vetor: vetor: " ) ; scanf scanf (" %d ", &n); &n); levet (vet, n); printf (" \n Maior valor = %lf ", maxval (vet, n) ); } void void leve levett (do (doub uble le v[ ], int int n ) /* “dou “doubl blee v[ v[ ];” ];” não não prec precis isaa dar dar a dim dimen ensão são */ { int i; double aux; printf("Entre os elementos do vetor:"); for for ((ii = 0; i < n; i++) i++) { scan scanff (("" %lf %lf ", ", &au &auxx );); v [ i ] = aux; } } doub double le maxv maxval al (dou (doubl blee v[ ], int int n ) { int i; double maior ; maior = v[ 0 ]; // maior começa como sendo o primeiro for (i = 1; i < n; i++) if (v [ i ] > maior maior)) maior maior = v [ i ]; return (maior); } Exercícios de Fixação 1) Escreva um algoritmo que preencha um vetor, de dimensão 100 (cem), com valores inteiros maiores que 0 (zero) e menores que 101 (cento e um), informados através do teclado, e que, após, visualize somente os valores múltiplos de 5, 5, sem utilizar o comando que forneça o resto de divisão automaticamente. automaticamente. 19
Escreva um algoritmo que preencha um vetor com valores inteiros, informados através do teclado, mas de tal modo que que nunca sejam armazenados 2 (dois) (dois) valores iguais nele. Mais ainda; após terminar o preenchimento o algoritmo dever dever visualizar todo conteúdo do vetor.
2)
3)
Escreva um algoritmo que preencha 2 (dois) vetores com valores inteiros maiores que 0 (zero) e menores que 101 (cento e um) , informados através do teclado, e que, após, processe a geração de um terceiro vetor que contenha todos os elementos dos dois primeiros vetores, porém sem que ocorra repetição de valores.
4)
Escreva um algoritmo que preencha um vetor com valores inteiros maiores que 0 (zero) e menores que 101 (cento e um), informados através do teclado, e que, após, visualize todos os valores presentes no vetor que façam parte dos primeiros 10 (dez) termos da série de Fibonacci.
5)
Escreva um algoritmo que preencha um vetor com valores inteiros maiores que –10 (menos dez) e menores que 10 (dez), informados através do teclado, e que, após, visualize, sem repetições, todos os valores ímpares presentes no vetor que façam parte dos 15 (quinze) primeiros termos da série de Fibonacci.
6)
Resolva os exercícios a seguir de 3 modos diferentes, ou seja: utilizando os comandos while { ... }; percorrendo o(s) do { . . . }, while { . . .} e for { . . .}. Mais ainda: as visualizações deverão ocorrer: percorrendo vetor(es) em ordem crescente e, após, em uma outra versão do exercício, percorrendo o(s) vetor(es) ordem decrescente. a)
Escreva um programa que preencha, preencha, a partir do teclado, duas estruturas distintas do tipo vetor com os nomes e as notas (as notas têm de estar contidas no intervalo 0 nota 10) dos alunos, respectivamente, de uma turma de 100 alunos e, após, exteriorize somente os nomes dos alunos que obtiveram notas iguais ou maiores que 5 (cinco).
b) Escreva um programa que preencha, preencha, a partir do teclado, duas estruturas estruturas distintas do tipo vetor com as idades de 100 pessoas. A primeira estrutura do tipo vetor deverá deverá receber somente as idades das pessoas do sexo masculino, enquanto a segunda deverá armazenar as idades das pessoas do sexo feminino. Após, o programa deverá exteriorizar os nomes, o sexo e as idades das pessoas que possuem idade compreendida compreendida entre 20 (vinte) e 40 (quarenta) anos, a nos, inclusive. 7) Escreva Escreva um algoritm algoritmoo que calcule calcule e visualize visualize a soma S conforme a representação abaixo.
S
( a1 – an ) 2 + ( a2 - an 1 ) 2 + ( a3 - an 2 ) 2 + ... + ( an - a1 ) 2
Os valores de a 1 a2 , ... , an deverão ser naturais consecutivos e o valor n deverá ser informado através do teclado, e estar compreendido no intervalo fechado [ 1 , 100 ] . Strings 8.1. “ Arryas” unidimensionais (vetores) de caractreres – Strings •
Considerações Gerais:
1. 2. 3. 4.
São arrays de caracteres. Em C, toda toda string string acaba com o caracter caracter '\0'. '\0'. Exemplo Exemplo da definiçã definiçãoo de um vetor vetor de caracte caracteres: res: char str str [ 7 ]; A consi consider deraçã açãoo 3 defin definee str como vetor de 6 caracteres mais o caractere de final fina l de string . Exemplo:char str [ 7 ]; str[0] = 'C'; str[1] = 'a'; 20
str[2] = 'r'; str[3] = 'l'; str[4] = 'o'; str[5] = 's'; str[6] = '\0';
Na memória teríamos:
C a r l o s \0
0 1 2 3 4 5 6
Podemos iniciar uma string de duas formas: 1º) Como um vetor: vetor: static char str [ ] = {'C', {'C', 'a', 'r', 'l', 'o', 's', '\0'}; // assume assume 6 caracteres caracteres mais '\0' = 7 2º) 2º) De Deix ixar ar que que o comp compil ilad ador or inic inicie ie:: stat static ic char char str[ str[ ]="C ]="Car arlo los" s";; // assu assume me 6 cara caract cter eres es mais mais '\0' '\0' = 7 Obs.: Obs.: Não é possíve possívell a atribuição atribuição direta: direta: char str[ 7 ]; str = "Carlos"; "Carlos"; /* Erro Erro:: não vale a atribuição atribuição */
// Exemplo: Fazer um programa para ler um nome e dar um bom dia para o dono do nome. // Solução 1: #include #define TAM 100 void main() { char linha [ TAM ]; int c, i; printf ( " \n Qual é o seu nome ? " ) ; for (i = 0; (c = getchar ( ) ) != '\n'; i++) linha [ i ] = c; linha [ i ] = '\0'; printf (" \n Tenha um bom dia " ) ; for (i = 0; linha [ i ] != '\0'; i++) putchar ( linha [ i ] ); putchar('\n'); } A função getchar retorna um caractere do teclado e a função putchar coloca um caractere no vídeo. Estas funções, bem como as outras de IO podem ser redirecionadas. redirecionadas. Em caso de erro, a função getchar retorna . EOF
// Solução 2: #include #define TAM 100 void main() { char linha [ TAM ]; printf (" \n Qual Qual é o seu nome nome ? " );); gets ( linha ); printf (" \n Tenha um bom dia !!!" ); 21
}
puts (linha);
A função gets tem por finalidade ler uma string e a puts imprimir uma string . A função puts fornece automaticamente uma mudança de linha após a impressão.
Formatos:
// Ponteiros Ponteiros serão abordados abordados com detalhes detalhes mais adiante) adiante) char *gets ( char *buf ); // Retor Retorna na pon ponte teir iroo para para a string lida ou NULL em caso de erro. int puts ( char *buf ); // Retorna '\n \n' se imprimiu bem ou EOF em caso de erro.
Para atribuição de strings, usa-se a função strcpy, que possui o formato: char *strcpy (char *destino, char *origem); Exem Exemplo plo:: strc strcpy py (str (str,, "cas "casa" a"); ); /* str passa a ter "casa" */ Para se saber o tamanho de uma função, usa-se a função strlen, que possui o formato: int strlen (char *st);
// Exercíc Exercício: io: const construir ruir a funç função ão strle strlen. n. // Solução 1: int strlen (char cadeia [ ] ) { int len = 0, I = 0; while (cadeia [ I ] != '\0') { ++len ; ++ i; } return ( len ); } // Solução 2: 2: int strlen ( char cadeia [ ] ) { int i; for for (i (i = 0; cade cadeia ia [ i ] != '\0' '\0';; i++) i++) ; return ( i ); }
/* bloc blocoo nulo nulo */
// Exercício: Construir uma função que copia uma string para um vetor de caracteres // Solução 1: void stringcpy (char[ ], char[ ]); void stringcpy (char s1[ ], char s2[ ]) { int i; for (i = 0; s2 [ i ] != '\0'; '\0'; i++) s1[ i ] = s2 [ i ]; s1[ i ] = '\0'; }
// Solução 2: void stringcpy(char s1[ ], char s2[ ]) { int i = 0; while while ( ( s1[ i ] = s2 [ i ]) != '\0' '\0' ) i++; 22
}
9. “ Arrays” bidimensionais (matrizes bidimensionais) Formato: [ ][ ]; Onde: d1 ⇒ número de linhas (varia entre 0 e d1 −1) d2 ⇒ número de colunas (varia entre 0 e d2 - 1) Exemplo: int b[3][5];
⇒
3 linhas e 5 colunas
Inicialização na declaração: static int b[ ][ 3 ] = { 1, 1, 1, 2, 2, 2, 3, 3, 3 };
≡
| | |
static int b[ ][3] = { {1, 1, 1}, {2, 2, 2}, {3, 3, 3} };
A iniciação também pode ser feita de forma esparsa. Por exemplo: static int b[ 3 ][ 3 ] = { {1, 1}, {1} }; A matriz gerada pela in inicialização acima se será: 110 100 000 Obs.: (1) Para este tipo de iniciação é necessário que se forneça o número de linhas e de colunas; (2) o armazenamento em C é feito por linhas; e (3) ao se passar uma matriz bidimensional, a única dimensão fixa é o número de colunas (ao contrário do Fortran que fixa o número de linhas).
// Exemplo void main ( ) { int mat[ 10 ][ 20 ]; ... f (mat, 10, 20); } A função f ( ) poderia receber a matriz de duas formas: void void f (int (int mat [10][2 [10][20], 0], int lin, lin, int col) col) void f (int mat [ ][20], ][20], int lin, int col) { comandos; }
ou
// Exempl Exemploo de de como como zerar zerar uma uma matr matriz: iz: void void zera zera (float (float mat[ mat[ ][ ][ 20 ],], int, int, int); int); /* prot protótip ótipoo */ 23
void main ( ) { float mat [ 10 ][ 20 ]; zera (mat, 10, 20); } void zera (float mat[ ][ 20 ], int lin, int col) { register int i, j; for (i = 0; i < lin; i++) for (j = 0; j < col; j++) mat[ i ][ j ] = 0.0; }
Exercícios de Fixação 1)
Escreva um algoritmo que preencha uma certa matriz quadrada de ordem 4 (quatro) com números inteiros, informados através do teclado, e que, após: a) Visu Visuali alize ze todo todoss núm númer eros os pert perten ence cent ntes es a Diag Diagon onal al Pri Princ ncipa ipall – DP DP ; b) b) Visu Visuali alize ze tod todos os núm númer eros os per perte tenc ncen ente tess a Diag Diagon onal al Secu Secund ndár ário io – DS DS ; c) Visu Visuali alize ze todo todoss núm númer eros os que que est esteja ejam m acim acimaa da Diag Diagon onal al Prin Princi cipal pal ; e d) Visual Visualize ize a soma soma de de todos todos os número númeross que que estejam estejam abaixo abaixo ddaa Diago Diagonal nal Secun Secundár dária. ia. 2) Escreva um algoritmo que preencha automaticamente uma certa matriz quadrada de ordem 8 (oito)
conforme a representação gráfica abaixo: colunas
linhas
1 2 3 4 5 6 7 8
1 2 A A A B A B A B A B A B A B A A
3 A B C C C C B A
24
4
A B C D D C B A
A B C D D C B A
5 A B C C C C B A
6
A B B B B B B A
7
A A A A A A A A
8
3) Escreva um algoritmo que preencha duas matrizes quadradas de ordem 3 com valores inteiros
maiores que 0 (zero) e menores que 101 (cento e um), informados através do teclado, sem permitir que sejam armazenados valores repetidos em cada matriz. visualizar todos os valores ímpares e múltiplos múltiplos de 11 sem, no entanto, Após, o algoritmo deverá visualizar utilizar o comando mod . Mais: após, o algoritmo deverá executar a geração automática de uma terceira matriz que represente a soma das outras duas matrizes, também sem permitir a ocorrência de repetição de valores. Quando ocorrer repetição o valor repetido deverá ser substituído por 0 (Zero) na matriz soma. Finalmente, o algoritmo deverá visualizar os valores presentes na terceira matriz – matriz soma – que façam parte dos 10 (dez) primeiros termos termos da série de Fibonacci.
4)
10.
Escreva um algoritmo que preencha duas matrizes de dimensões 5x3 e 3x2, respectivamente, e que, após, calcule e visualize a matriz produto delas.
Funções
Formato: < tipo > < nome da função > ( < parâmetros > ) { declaração de variáveis locais; corpo da função; } • • •
• • •
< tipo > é o tipo do valor a ser retornado pela função; se uma função não retorna valor, o seu tipo tip o é void; os parâmetros são sempre passados por valor, isto é, uma cópia do valor da variável é passado para a função; para arrays (vetores e matrizes) é passado como valor o endereço da primeira posição; deve-se deve-se sempre usar o protótipo da função; variáveis 'char' são transformadas em 'int' e variáveis 'float' são transformadas em 'double'.
O formato da função varia entre o padrão K & R e o ANSI. O padrão K & R pode ser usado no ANSI. ANSI. formato K & R int soma (a, b) int a, b; { return (a+b); }
|
| | | | |
}
formato ANSI int soma (int a, int b) { return ( a + b );
O valor retornado por uma função pode ou não ser utilizado (e.g.: a função printf ( ) ). i nstrução return ( ). Mais: pode-se retornar de qualquer ponto da função, bastando usar a instrução // Exemplo: Fazer um programa para ler um número e imprimir o seu fatorial utilizando uma 25
// função para ler o número, uma para cálculo do fatorial e uma para mostrá-lo. # include long factorial (long); long leval (void); void printfat (long); void main ( ) { long fat, val; val = leval ( ); fat = factorial (val); printfat (fat); } long leval ( ) { long x; printf (" \nEntre o valor a ser calculado: "); scanf("%ld", &x); return ( x ); } void printfat (long y) { printf (" \nFatorial = %ld\n", y); } long fatorial (long a) { long fator = 1; long i; for (i = 1; 1; i <= a; i++) fator *= i; return ( fator ); } 11. 11.
O Tip Tipoo ““Po Poin inte ter” r” (Pon (Ponte teir iro) o)
11.1 11.1.. Defi Defini niçã çãoo Um ponteiro é uma variável que contem como valor um endereço. Para definirmos uma variável como ponteiro, devemos devemos fornecer o tipo da variável para qual apontará e um nome. Embora os endereços de variáveis de um tipo (e.g.: int), sejam semelhantes aos de outros tipos como float, indicar o tipo de char ou double, é importante não misturá-los. Para a declaração de um ponteiro tem-se que indicar variável para o qual ele irá apontar, pois ao serem feitas operações aritméticas com os ponteiros, eles irão variar em função de seu tipo. Principais vantagens do uso: • superar as restrições de passagem de argumento, por valor, para funções; • acessar elementos de arrays de modo alternativo ao uso de índices; • permitir a criar estruturas dinâmicas (árvores e listas encadeadas) bem como suas manipulações. Forma de definição: *; Exemplos:
int *p; ⇒ p é um ponteiro para inteiro float *pf; ⇒ pf é um ponteiro para float int i, *pt; ⇒ pt é um ponteiro para inteiro pt = &i; ⇒ pt receb recebee oend oendere ereço ço de i 26
i
pt
5
1 002
1002
2 0 00
*pt
⇒
5 (cont (conteúd eúdoo do end ender ereço eço dado dado por pt) pt)
void *pvoid; ⇒ ponteiro para qualquer tipo Dado: float x, y, *p, *q; Temos como operações possíveis: p = &x;
⇒
p aponta para x
y = *p;
⇒
y recebe o valor que está no endereço dado por p
q = p;
⇒
q e p apontam para o mesmo endereço endereço
Erros comuns: int *p; *p = 10; float val; int *p; p = &val;
// não apontou para nenhuma variável
// tipos incompatíveis
11.2. 11.2. Iniciaç Iniciação ão de ponteir ponteiros os na definiçã definiçãoo int i = 7, p = &i;
/* a inicialização é de p e não de *p */
11.3. Passagem Passagem de de parâmetros parâmetros por por endereço endereço (referência) (referência) Para que se possa passar uma variável por referência, devemos passar um ponteiro para esta variável ou, em outras palavras, o seu endereço. endereço. /* Exemplo: ler dois valores e trocá-los de ordem */ #include void void swap swap (int (int *, *, int *); *); /* protót protótipo ipo de swap swap */ void main( ) { int a, b; scanf (" %d %d", %d", &a, &b); /* le os os dados dados */ swap (&a, &b);
/* chama a função swap */ 27
}
printf ("%d : %d\n", a, b);/ b);/** imprime resultado */
void swap(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; }
// Exemplo: fazer uma função que tenha o seguinte protótipo: void soma (int *r, int a, int b); # include void void som soma( a( int int *r, *r, int a, int b); b);
// Os Os nome nomess dos dos parâme parâmetro tross estã estãoo decla declarad rados os por opç opção. ão.
void main ( ) { int x, y, z; printf ( " \n Entre Entre dois números: \n"); scanf ("%d %d", &x, &y); soma (&z, x, y); printf (" \n A soma é: %d\n", z); } void soma (int *r, int a, int b) { *r = a + b; }
12. A rela relação ção entre entre ponteir ponteiros os e Arrays Um nome de array é um endereço ou ponteiro, que é fixo.
// Exemplo: int k, a[100], *p; p = a;
//
p possui o endereço do primeiro elemento de a
// ou p = &a[ &a[ 0 ]; ]; // p possui o endereço do primeiro elemento de a
Para que p aponte para o elemento seguinte, basta incrementar o endereço de 1. p = a + 1; // p = &a [ 1 ] ; p++; // p aponta para o próximo elemento. p e p aponta para o próximo elemento k = *p++; // k ← valor do elemento apontado por p
// Exempl Exemplos os para para zerar zerar um um vetor vetor:: for (i = 0; i < 100; i++) a[ i ] = 0;
// com índice 28
ou for (i = 0, p = a; i < 100; i++ i++) *p++ = 0;
// com ponteiro
// Exemplo: Criar uma função que retorne o tamanho em em bytes bytes de de uma cadeia de de caracteres // usando ponteiro. // Solução 1: # include int strlen (char* str); void main ( ) { static char str [ ] = "Esta string string tem 30 caracteres."; caracteres."; printf (" \nTamanho da string: %d caracteres.\n", strlen (str) ); } int
strlen (register char *s)
{ }
// Solução 2: # include int strlen (char *str); void main ( ) { } int int { }
register int n; for (n = 0; *s != '\0'; s++) ++n; ++ n; return ( n );
static char str[ ] = "Esta string tem 30 caracteres."; printf ("\nTamanho da string : %d caracteres.\n", strlen (str) );
strl strlen en(r (reegist gister er char char *s) *s) register int n=0; while (*s++)++n; return(n);
// Solução 3: #include int strlen (char *str); void main ( ) { stat static ic cha charr str str[[ ] = "Est "Estaa stri string ng tem tem 30 30 car carac acte tere res. s."; "; printf (" \n Tamanho da string : %d caracteres.\n", strlen (str) ); } int {
}
strlen (register char *s) register char *ps; p s = s; // ps aponta para o inicio da string whil wh ilee (*p (*ps) s) ps++ ps++;; return(ps - s);
// Exemplo: Criar a função strcpy, strcpy, que copie o conteúdo conteúdo de uma string em outra. # include char *strcpy (char *d, char *o); void main ( ) { stat static ic char har or orig[ ig[ ] = "t "teste ste", dest [ 20 20 ]; ]; strcpy (dest, orig); 29
}
printf("origem = %s ; destino = %s\n", dest, orig);
char *strcpy (char *dest, char *origem) { char *d = dest; // O while a seguir faz a copia e incrementa os ponteiros de cada string , até aparecer um // caractere nulo significando fim de string. // Alguns compiladores darão um um aviso (warning) , achando que se deseja fazer um teste ao // Invés de de atribuição com teste, teste, que é o que se pretende fazer realmente. while while (*d++ (*d++ = *origem *origem++); ++); /* sem sem bloco bloco */ return (dest ); }
// Exemplo: Criar a função strcmp que tem tem como finalidade comparar o conteúdo conteúdo de uma // string com o de outra. A função tem o seguinte formato: int strcmp (char *s, char *t); // Esta função retorna: (a) 0 se as strings forem iguais; (b) < 0 se s < t ; e (c) > 0 se s > t # include int strcmp (char *s, char *d); void main ( ) { char s1 [ 20 ], s2 [ 20 ]; printf (" \nEntre \nEntre a primeira primeira string: string: "); gets ( s1 ); printf (" \nEntre a segunda string: "); gets ( s2 ); if ( strcmp (s1, s2) ) prin printf tf (" (" \n \n Dif Difeerent rentes es.\ .\nn"); "); /* <> de zer zeroo */ */ else printf (" \n Iguais.\n"); } int strcmp (char *s1, char *s2) { while (*s1 == *s2) if (*s1++) s2++; else return(0); return(*s1 - *s2); } Para definição e iniciação de strings , também é possível o seguinte tipo tip o de instrução: char *mens = "Divisão por zero"; A definição acima define mens como sendo um ponteiro para a string "Divisão por zero". 13. 13.
Pont Pontei eiro ross e arra arrays ys bidi bidimen mensi sion onais ais
Como para vetores unidimensionais, o nome de um array é um ponteiro fixo. Assim, as seguintes instruções são equivalentes e geram o mesmo código: b[ i ][ j ]
*(*(b + i) + j)
*(b + i * ncolun + j)
O esquema abaixo representa o acesso à vetores bidimensionais.
30
b b[1] b[i] b+i *(b + i)
b[i][j] = *(*(b + i)
Como para vetores unidimensionais, existem formas de se acessar matrizes de uma forma mais eficiente, como veremos a seguir. Definição de ponteiros para matrizes. int mat[10][20], (*plin)[20]; plin = mat; Nas instruções acima, definimos plin como sendo um ponteiro para uma linha de um array com 20 colunas e mandamos que ele aponte para o primeiro elemento. Forma de armazenamento na memória: ..
..
..
.
.
.
20 elementos
20 elementos
20 elementos
Para acessar um elemento da matriz via ponteiro: (*plin (*plin)[ )[j] j] ou *(*(p *(*(plin lin)) + j) Para se passar para a próxima linha: plin++;
plin
plin + 1
plin + 9
define um ponteiro ponteiro para linha de um vetor vetor com 20 20 colunas, enquanto enquanto que Nota: ( * plim) [ 20 ] define *plin[20] define um vetor de 20 elementos do tipo ponteiro.
// Exemplo: Exemplo: Calcula Calcularr a média dos element elementos os de uma coluna coluna de uma matriz matriz de 3 colunas. colunas. // Solução: # include double test_avg (int (int [ ][ 3 ], int, int); void main ( ) { double res; static int board [ ][ ][ 3 ] = {
}; res = test_avg ( board, 4, 2 );
1, 4, 7, 10,
2, 5, 8, 11,
3, 6, 9, 12
31
printf (" %lf\n", res);
} double {
test_avg (int tab[ ][3], int maxlin, int col) long sum = 0; int i, (*ptr)[3] = tab; for (i = 0; i < maxlin; i++) sum += (*ptr++) [col ]; return ( (double) sum / maxlin );
}
// Exemplo: calcular a média dos elementos de uma linha de uma matriz de 3 colunas. // Solução: # include double test2_avg ( int[ ][ 3 ], int); void main ( ) { static int board[ ][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; double res; res res = test test2_ 2_av avgg (boa (board rd,, 1); 1); printf (" %lf\n", res);
}
/* calc calcul ular ar para para linh linhaa 1. 1. */
double test2_avg(int tab[][3], int linha) { long soma = 0; int i; int *p = &tab[linha][0]; for (i = 0; i < 3; i++) soma += *p++; return ( (double) soma / 3 );
}
Not Notas: as:
&tab &tab[n [n][ ][0] 0] = ende endere reço ço do elem elemen ento to (n, (n, 0) em tab tab[n] = linha “n “de tab
O nome de um array bidimensional quando usado com um único índice é um ponteiro p onteiro para o primeiro elemento de uma determinada linha.
13.1
−
Arrays tridimensionais:
Seguem as mesmas regras do bidimensional. Exemplo: int v [ 3 ][ 4 ][ 5 ] define um array v com dimensões 3 x 4 x 5. Definição de um vetor 3D em funções: int vet[ ][ 4 ][ 5 ]
ou int (*vet)[ 4 ][ 5 ] 32
13.2
Arrays de ponteiros (ragged arrays )
São arrays com linhas de tamanho variável. Um array deste tipo é composto por ponteiros para outras variáveis e o seu uso mais comum é para acessar tabelas de strings. Exemplo: definir um vetor de ponteiros para uma tabela t abela de dias da semana. static char *dias[ ] = { "segunda", "terça", "quarta", "quinta", "sexta", "sábado", "domingo" "domingo" }; Para esta definição, dias é um array de 7 ponteiros para caracteres. c aracteres. O esquema a seguir apresenta a organização interna i nterna da tabela de dias da semana. dia s 0
s e g u n d a \0 \0
1 . . . 6
t
e r
ç
d o m i
a \0
n g o \0
Os elementos de 'dias' podem ser acessados de duas maneira: 1. dias [ i ] printf ("%s\n", dias[2]);
// será impresso "quarta"
2. dias [i [i ][ j ] printf ("%c\n", dias[ 1 ][ 2 ]); // será impresso ' r ' // dias [ 1 ] ⇒ "terça" e dias [ 1 ][ 2 ] ⇒ r (de "terça") // Exemplo: Fazer uma função função para imprimir 'dias'. #i nclude void printab printab (char *[ ], int); void printab (char *tab[ ], int n) { int i; for (i = 0; i <= n; i++) printf(" %s\n ",tab [ i ]); }
33
Nota: Um elemento em um array de pointers pode ser usado como se ele fosse um pointer para o primeiro elemento de uma linha de um array bidimensional (tab [ i ]).
14. Alocação Dinâmica de Memória A linguagem C possui uma série de funções que permitem alocar e liberar áreas de memória, fazendo com que se possa usar a memória gasta por variáveis, vetores, vetores, matrizes, listas, pilhas, etc. de uma forma mais eficiente. Quando necessário, o usuário pede uma área e a utiliza e, quando esta área não for mais necessária, ela é devolvida devolvida ao sistema operacional, de forma a poder ser utilizada em outra etapa do programa. O esquema abaixo apresenta o mapa da memória de um programa em C. Área de Código Área de Variáveis Estáticas e Globais Stack Heap A área disponível para alocação dinâmica se encontra na Heap. As principais funções para manipulação de memória memória estão definidas no header stdlib.h e são: malloc calloc • realloc • free • •
void *malloc(unsigned int); ptr = malloc(tam); Aloca uma área de tam bytes. Se alocou corretamente, retorna um pointer para o primeiro byte da área alocada e em caso de erro retorna NULL.
// Exemplo 1: int *ptr; ... ptr = malloc(sizeof(int)); if (p (ptr == NULL) { *ptr = 10; ...
}
printf(" \nErro de alocação"); exit ( 1 );
// Exemplo 2: int *ptr, *ptraux, i; ... ptr = malloc(sizeof(int) * 100); if (ptr == NULL) { printf("Erro de de alocação"); exit(1); } ptraux = ptr; for (i = 0; i < 100; i++) *ptr++ = i; 34
ptr = ptraux; ... •
Vetores gerados dinamicamente
// Obtém Obtém área para um vetor vetor do tipo float. float. O número número de element elementos os é pedido pedido pelo programa. programa. // Após a obten obtenção ção da área área necessária necessária são pedidos pedidos dados dados para o seu seu preenchimento preenchimento.. # include # include void prtvet (float*, int); void main ( ) { int num, i; float *pvet, *pinic; printf ("\nEntre com número de elementos:\n"); scanf ("%d", &num); pvet = (float*) malloc(num * sizeof(float)); if (!pvet) { printf printf (" \nE \nErro rro.. Falta Falta de memór memória.\ ia.\n" n"); ); exit ( 1 ); } pinic = pvet; for (i = 0; i < num; i++) { printf (" \n%d -> ", i + 1); scanf ("%f", pvet++); // Não funciona no Turbo C } pvet = pinic; prtvet(pvet, num); // Imprime o vetor free(pvet); } void prtvet (float *p, int n) { int i; for (i = 0; i < n; i++) printf("\n\%d -> %f", i + 1, *pv++); } void *calloc (unsigned int, unsigned int); ptr = calloc(num, size); Aloca uma área de 'tam' * 'num' bytes. Se alocou corretamente, retorna um pointer para o primeiro byte da área alocada e em caso de erro retorna NULL. A área alocada é automaticamente automatic amente zerada.
// Exemplo 1: int *ptr; ... ptr = calloc(1, sizeof(int)); if (ptr == NULL) { printf (" ("Erro de alocação"); exit (1); } *ptr = 10; ... // Exemplo 2: 2: int *ptr, *ptraux, i; ... 35
ptr = calloc(100, sizeof(int)); if (ptr == NULL) { prin printf tf (" \nErro de alo alocaç cação" ão"); exit ( 1 ); } ptraux = ptr; for (i = 0; i < 100; i++) *ptr++ = i; ptr = ptraux; ... void free ( void *); free (ptr); void *realloc (void *, unsigned int) nptr = realloc(old, tam); A função realloc altera o tamanho da área alocada por malloc ou calloc. O novo tamanho pode ser maior ou menor do que o tamanho original. Quando chamada, retorna um pointer para a nova área alocada, sendo old um pointer para a área antiga e tam' o novo tamanho em bytes. Em caso de erro, a função retorna NULL e o programa deve ser interrompido, já que a área original poderá estar comprometida. Exemplo: #include #include void prtvet(float*, int); void main ( ) { int num, i; char *p; p = (char*) malloc(23); strcpy (p, "AQUI TEM 22 CARACTERES"); printf ("\n%s\n", p); p = realloc (p, 24); strcat(p, "."); printf(" \n%s\n", p); free ( p ); }
Libera a área alocada por malloc, calloc ou realloc. // Exemplo: int *ptr, *ptraux, i; ... ptr = malloc(sizeof(int) * 100); if (ptr == NULL) { prin printf tf (" \nErro de alo alocaç cação" ão"); exit ( 1 ); } ptraux = ptr; for (i = 0; i < 100; i++) *ptr++ = i; ptr = ptraux; ... free (ptr); ... 15. 15. Defin efiniç ição ão de de nov novoos tip tipos os •
Para definição de novos tipos, é utilizada a instrução typedef . 36
Formato: typedef ;
// Exemplos: // Para Para se defi definir nir o tipo tipo 'con 'contad tador' or':: typedef int contador; contador i, j; // É o mesmo que int i, j Para se definir o tipo string : typedef char string [ 81 ]; string text;
// É o mesmo que char text[81]
Para se definir o tipo 'boolean': typedef int boolean; # define FALSE 0 # define TRUE 1 ... boolean ok = TRUE; if (ok) . . . pointer para caractere): Para se definir o tipo ptrchar ( pointer typedef char *ptrchar; ptrchar pchar; // É o mesmo que char *pchar
16.
Estruturas struct
Uma etrutura – struct – é usada quando há necessidade de se combinar combinar dados de um mesmo tipo ou de tipos diferentes em um único objeto ou registro.
Forma de definição: struct {
}; Exemplos: struct s1 { int a; char nome [ 81 ]; char ender [ 100 ]; };
< campo 1 , campo 2 , . . . , campo n>; < campo 1 , campo 2 , . . . , campo n>; : < campo 1 , campo 2 , . . . , campo n>;
// Define estrutura chamada s1 contendo os seguintes campos // // // //
Define um campo do tipo inteiro denominado a Define um array de caracteres denominado nome Define um array de caracteres denominado endereço Aqui, a struct s1 passa a ser um tipo
// Agora é possível utilizar a struct s1 para definir duas variáveis estruturadas: info1 e info2 struct s1 info1, info2; •
Uma outra forma de definirmos este tipo de variáveis é: struct { int x, y ; } v1, v2;
// No exemplo acima, não foi criado um tipo, e sim duas variáveis (v1 e v2) do tipo struct // Também é possível o uso do do typedef em conjunto com as estruturas: 37
typedef struct s1 t_s1; t_s1 in info1, iinnfo2;
// Fo Foram cr criadas du duas va variáveis info1 e info2 do tipo struct t_s1
Acesso aos membros de uma estrutura: .; Exemplos: info1.a = 10; strcpy(info1.nome, strcpy(info1.nome, "teste"); struct s2 { int a; char *nome; };
/* nome é um ponteiro */
struct s2 info3; info3.a = 10; info3.nome = "José da Silva";
/* nome é um ponteiro */
Operações possíveis entre estruturas: A partir da definição: struct s1 v1, v2; temos: 1) atribuição: v1 = v2; 2) comparação (somente igualdade e desigualdade) if (v1 == v2) { ... } É possível perguntarmos se duas estruturas estruturas são iguais igua is ou diferentes, mas não se uma é maior ou menor do que a outra. No entanto, os campos (membros) de uma estrutura podem ser comparados com os de outra. Apesar de na versão ANSI podermos passar estruturas por valor para as funções, isto deve ser evitado, evitado, já que stack torna a chamada da função mais lenta e aumenta a área ocupada no . A forma mais indicada para se passar p assar estruturas é utilizar pointers, como será visto mais adiante.
16.1 16.1 Inici Iniciaçã açãoo de estru estrutu tura rass Para alguns compiladores, é necessário necessário que as variáveis locais sejam estáticas. struct s_carta { int carta; char naipe; }; struct s_carta c = { 12,
/* Ouro, Copas, Paus e Espadas */
38
};
'O'
/* inicializa como dama de ouros */
16.2 6.2 Ca Camp mpos os de bit bitss Os campos de bits ou bitfields tem como principal finalidade a economia de memória, porém em alguns casos o código gerado para a sua manipulação pode ser grande, gastando mais memória do que economizando. Forma de definição: struct { 1> 1> : ; : ; ... : ; }; // Obs.: Obs.: pode pode ser: int, int, unsigned unsigned int e signed signed int. // Exemplo: struct baralho { unsigned carta : 4; unsi un siggned ned nipe ipe : 2; }; struct baralho x; x.carta = 9; x.nipe = 2;
/* 0 a 15 */ /* 0, 1, 2, 3 */ /* ouro ouros, s, copa copas,e s,esp spad adas as,, paus paus */
/* 9 de espadas */
Ao contrário de estruturas normais, os bitfields não podem ser usados com pointers .
16.3 Uniões Permitem armazenar em uma mesma região valores de tipos diferentes. Forma de definição: union { ; ; ... ; };
// Exem Exempl plo: o: union mixed { char c; float f; int i; }; union mixed x; x.c = 'A'; ... x.f = 10.0; ... x.i = 1; 39
A área reservada para uma variável deste tipo é calculada pelo tamanho do maior campo. No exemplo exemplo acima, a área reservada teria o tamanho de um float . Devemos notar que uma variável deste tipo guarda apenas um valor de cada vez, isto é, ao armazenar o dado de um novo tipo apaga o do tipo anterior. A seguir é apresentado um exemplo no qual se monta em array de estruturas que guarda elementos de "tipos" " tipos" diferentes. /* Exemplo Exemplo do uso uso combinado combinado de de estrutura estrutura e união: união: Cria um array denominado tabela e dimensão TAMANHO. Cada elemento do array contem uma estrutura que consiste de um ponteiro para caractere (nome), um inteiro (tipo) e um membro do tipo union chamado "dados". Cada membro dados do array pode conter int , float ou char . */ # include # define INTEGER 0 # define FLOATING 1 # define CHAR 2 # define TAMANHO 6 void main ( ) { Struct Struct S1 { char *nome; int tipo; union { int i; float f; char c; } dados; } tabela [TAMANHO]; [TAMANHO]; // Cria uma um vetor de estruturas denominado tabela int j; // Inicia os os elementos da estrutura tabela[ 0 ].nome tabela[ 0 ].tipo tabela[ 0 ].dados.c tabela[ 1 ].nome tabela[ 1 ].tipo tabela[ 1 ].dados.c
= = = = = =
"Cesar"; CHARACTER; 'A'; "do Vale "; CHARACTER; 'A';
tabela[ 2 ].nome = "Ferrari "Ferrari "; tabela[ 2 ].tipo = CHARACTER; tabela[ 2 ].dados.c ].dados.c = 'A'; tabela[ tabela[ 3 ].nom ].nomee = "Idad "Idadee "; tabela[ 3 ].tipo = INTEGER; tabela[ 3 ].dados.i ].dados.i = 42; tabela[ 4 ].nome = "Salário "; tabela[ 4 ].tipo = FLOATING; FLOATING; tabela[ 4 ].dados.f ].dados.f = 7200.56; tabela[ 5 ].nome
= "Imposto "Imposto "; 40
tabela[ tabela[ 5 ].tipo ].tipo = FLOAT FLOATING ING;; tabela[ 5 ].dados.f = 2785.89; for (j = 0; j < TAMANHO; TAMANHO; j++) { printf (" %s ", tabela[ j ].nome); switch (tabela[ j ].tipo) { case INTEGER: printf (" %d\n", tabela[ j ].dados.i); break;
}
}
}
case FLOATING: printf (" %.2f\n", tabela[ j ].dados.f); break; case CHARACTER: printf ("%c\n", tabela[ j ].dados.c); ].dados.c); break; default: printf ("Tipo desconhecido %d - elemento elemento %d.\n", tabela[ j ].tipo, j); break;
16.4 Pointers para Estruturas Como vimos anteriormente, devemos devemos passar as estruturas através de pointers e não por valor. Isto deve ser feito mesmo que não alteremos nenhum dos campos da estrutura. /* Exemplo - Pointer para estruturas */ #include struct s_data { int dia, mes, ano; }; typedef struct s_data sdata; void prtdata (sdata *); void main ( ) { sdata data; data.dia = 15; data.mes = 3; data.ano = 1988; prt prtdat data ( &da &datta); a); /* pass passaa o en endere ereço da es estrut trutur uraa data */ } void prtdata(sdata *data) { printf(" printf(" %d/% d/ %d \n", (*dat (*data).di a).dia, a, (*data). (*data).mes, mes, (*data). (*data). ano); ano); } Existem duas formas de se acessar os valores de uma estrutura através de pointers: componente te > ou < pointer > < componente >; (* < pointer >).< componen Exemplo: sdata data, *pdata; pdata = &data; 41
(*pdata).dia = 31; (*pdata).mes = 12; (*pdata).ano = 1989;
// ou pdata−>dia = 31; // ou pdata−>mes = 12; // ou pdata−>ano = 1989;
16.5. 16.5. Pontei Ponteiro ro para para perco percorrer rrer array de ponteiros. Como para os outros arrays, o nome de um array de ponteiros é um ponteiro para o primeiro elemento do array. Quando se passa um array de ponteiros como parâmetro, o que realmente se passa é um pointeiro para o primeiro elemento do array.
// Exemplo: Imprimir tabela 'dias'. typedef char *CHARPTR;
/* define ine tipo ipo pointer par para ch char */ */
void void print_ta print_tab(CH b(CHARP ARPTR TR *tab_ *tab_ptr ptr,, int n) { CHARPTR *e *end_ptr = tab tab_ptr + (n - 1); while (tab_ptr <= end_ptr) printf (" %s\n", *tab_ptr++); }
Esquema dos ponteiros : tab_ptr 0
s e g u n d a \0 \0
1 .. .
end_ptr 6
17.
t
e r
ç a \0
d o m i
n g o \0
Ponteiros para funções
Permitem passar funções como argumentos. Forma de definição: < tipo > (* func_ptr ) ( < tipos dos argumentos > ); parênteses, estará sendo defininda uma função que retorna um pointer para Nota: se não forem colocados os parênteses, .
// Exemplo: int soma (int, int); void main ( ) { int (*ptr_soma) (int, int); ptr_soma = soma; // pointer para função soma x = (*ptr_soma) (3,5); // x ← soma (3, 5); } // Exemplo: Fazer um programa que leia duas cadeias de caracteres numéricos ou alfanuméricos e as compare conforme o seu tipo. # include # include 42
# include int numcmp (char *, char *); void check (char *, char *, int (*cmp) (char *, char *)); void main ( ) { char s1[ 80 ], s2[ 80 ]; gets (s1); // obtém a primeira cadeia gets (s2); // obtém a segunda cadeia if (isalpha (*s1) )
}
// isalpha devolve um valor ≠ de zero se no endereço apontado por s1 // houver um caractere alfabético ou zero em caso contrário check check (s1 ,s2, ,s2, strcmp strcmp); ); // comput computaa como como caract caractere eress else check (s (s1, s2 s2, nu numcmp); // comp. co como nú números
void check (char *a, char *b, int (*cmp)(char *, char *)) { if ( ! ( *cmp) (a, b) ) printf(" \n Iguais.\n"); else printf ("\n Diferentes.\n"); } int numcmp(char *a, char *b) { if (atoi ( a ) == atoi ( b ) ) return ( 0 ); else return ( 1 ); } Observações sobre o exemplo: •
a função strcmp compara strings;
•
a função isalpha retorna <> 0 para letra do alfabeto; e
•
a função atoi transforma uma string em número inteiro
18. Tipo en enumera erado Faz com que uma variável possa ter somente um valor dentre um conjunto determinado de valores. Forma de definição: enum {}; Exemplo: enum dia {segunda, terça, quarta, quinta, sexta, sábado, domingo}; 0 1 2 3 4 5 6 Este exemplo define o tipo dia. Uma variável deste tipo somente poderá receber um dos valores dados entre parênteses. enum dia, dia1, dia1, dia2, dia2, todos todos[7]; [7]; /* define define variáv variáveis eis */ dia1 = segunda; todos[6] = domingo; 43
Note que os valores entre parênteses não são sã o strings. Uma outra forma de definição possível é: enum {segunda, ..., domingo} dia1, dia2; Se usarmos as definições acima, a cada valor do tipo enumerado será associado um valor inteiro, a partir de zero (0). Entretanto, podemos indicar os valores inteiros que desejamos associar: enum frutas {laranja = 7, lim,o = 6, jaca = 0}; enum frutas {pera = 2, laranja, abacate, lim,o = 7}; Apesar das definições acima, os valores dos tipos enumerados não são inteiros. Erros:
dia1 = 1.0; dia2 = 2;
Para usarmos o valor inteiro associado, devemos usar um "cast" para inteiro: i = (int) dia1;
19.
Arquivos
A linguagem C possui alguns arquivos pré-definidos e que são automaticamente abertos quando um programa começa a ser executado. Eles são: stdin stdout stderr stdp stdprn rn
standard standard standard stan standa darrd
input output error prin printe terr
(default = teclado) (default = vídeo) (default = vídeo) (som (somen ente te algu alguns ns comp compil ilad ador ores es))
Os arquivos pré-definidos p ré-definidos stdin, stdout e stderr podem ser redirecionados pelo usuário. O arquivo stdprn é dependente do compilador, podendo existir ou não. Para estes arquivo pré-definidos, a leitura e impressão se passam como se estivéssemos utilizando um arquivo texto (leitura e gravação seqüenciais). O conceito de arquivos em C é um pouco diferente do de outras linguagens. Na maioria das linguagens, o tipo ti po de acesso (direto ou seqüencial) seqüencial) está diretamente ligado à forma de abertura do arquivo, o que não acontece em C. Em C, o acesso a um arquivo pode ser direto ou seqüencial, sendo que esta escolha é feita conforme as necessidades do usuário. O C possui funções que permitem o acesso tanto direto quanto seqüencial e permitem um acesso bastante eficiente à arquivos. 44
Forma de definição: FILE *fp; Para que esta definição esteja correta, é necessário que o arquivo stdio.h tenha sido incluído.
19.1. 19.1. Funções Funções para abert abertura ura e fechame fechamento nto de de arquivos arquivos 19.1 19.1.1 .1..
Aber Abertu tura ra de de arqui arquivo vos: s: FILE *fopen (char *, char *); fp = fopen (nome, modo);
Esta função abre o arquivo de nome "nome" com o modo "modo"."nome" e "modo" são strings de caracteres. Os modos de abertura abertura possíveis são apresentados na tabela abaixo: Modo r r+ rb rb+ w w+ wb wb+ a a+ ab ab +
Tipo t t b b t t b b t t b b
Read s s s s n s n s n s n s
Write n s n s s s s s s s s s
Cria n n n n s s s s s s s s
Append n n n n n n n n s s s s
Onde: • rread • w write • a append • ttexto • b binário • s sim • n não 45
Em caso de sucesso na abertura, a função fopen retorna um ponteiro para o arquivo, o qual será utilizado como nome lógico do arquivo dentro do programa e, em caso de erro, retorna NULL. É responsabilidade do usuário verificar se o arquivo foi aberto ou não. Exemplo: fp = fopen fop en ("teste.dat", "r"); "r"); if (fp == NULL) // ou if (!fp) → fp foi declarado antes como FILE *fp { printf printf(" (" \n Erro: Erro: abertu abertura ra de arqui arquivo vo para para leit leitura ura"); "); exit ( 1 ); /* retorna para o sistema sistema operacional */ } O nome do arquivo pode indicar um nome simples ou um nome com path (caminho). Exemplos de nomes: "teste.dat" "C:\programas\testes\teste.dat" A diferença básica entre os modos texto e binário reside no fato de que quando os arquivos são abertos no New Line) é convertido em dois: CR (Carriage Return ) e LF modo texto para gravação, o caractere NL ( New LineFeed ) e quando são abertos no modo texto para leitura, ocorre o inverso. Para arquivos abertos no modo ( LineFeed binário, esta conversão não existe, havendo, portanto, uma correspondência de 1 para 1.
19.1 19.1.2 .2..
Fech Fecham amen ento to de arqu arquiv ivos os:: int fclose(FILE *); fclose(fp);
Em caso de sucesso a função fclose ( ) retorna NULL. Em caso de erro um valor diferente de zero. Exemplo: if ((fp = fopen ("teste.dat", "r")) == NULL) { printf printf (" \n Erro Erro de abertu abertura ra para leitura leitura"); "); exit (1); } ... fclose(fp);
19.2. 19.2. Princip Principais ais funç funções ões para para leitura e gravação seqüenciais Leitura:
•
char *fgets(char *, int, FILE *); pchar = fgets(buffer, num, fp); fp. A leitura termina quando forem lidos num – 1 caracteres, ou quando Lê caracteres do arquivo dado por fp New Line) ou EOF ( End End Of File). encontrar o caractere NL ( New
Os caracteres lidos são colocados em um buffer. Se a leitura foi correta, a função retorna um pointer para o buffer e em caso de erro retorna NULL. O buffer deve ser grande o suficiente para que sejam colocados os caracteres '\0' e NL. Exemplo: char *pchar, buffer[ 100 ]; 46
FILE *fp; ... pchar = fgets(buffer, 98, fp); ... int fgetc (FILE *); v_int = fgetc ( fp ); Lê um caractere do arquivo dado por fp e retorna o seu código ASCII. Se a leitura chegar ao final do arquivo ou houver erro de leitura, é retornado EOF. Entretanto, deve-se usar esta função com certo cuidado, já que EOF pode ser um caractere válido em arquivos abertos no modo binário. int fscanf (FILE *, char *, ...); ...); fscanf(fp, fmt, args); Funciona de forma semelhante à função scanf . Le as variáveis em args com o formato fmt do arquivo dado por fp. Em caso de sucesso, retorna o número de variáveis que foram lidas. Caso se chegue ao final do arquivo, é retornado EOF. •
Gravação:
int fputs (char *, FILE *); fputs (str, fp); Grava a string str no arquivo dado por fp. A função retorna zero (0) se gravou bem e outro valor em caso de erro. int fputc (int, FILE *); fputc (carac, fp); Grava o caractere que está na variável carac no arquivo dado por fp. Em caso de erro, retorna EOF, porém se o arquivo for aberto em modo binário, EOF poderá ser um caractere válido. int fprintf (FILE *, char *, . . . ); fprintf (fp, fmt, args); Funciona de forma semelhante à função printf . Grava as variáveis em args com o formato fmt no arquivo dado por fp. Em caso de sucesso, retorna o número de caracteres que foram gravados e em caso de erro, retorna um número negativo.
// Exemplo: fazer um programa que copie um arquivo em disco para outro. Os nomes dos // arquivos são fornecidos como parâmetros na linha de comando, sendo o primeiro o // nome do arquivo origem e segundo o nome do arquivo destino. #include #include #include void main (int argc, char *argv[]) { char buffer [ 512 ]; char arqorg [ 150 ], arqdst [ 150 ]; FILE *nome1, *nome2; if (arg (argcc < 3) {
prin printf( tf("" \n \n Err Erro: o: Nú Núme mero ro de parâ parâme metr tros os inco incorr rret eto" o"); ); exit ( 1 );
} strcpy (arqorg, argv [ 1 ] ); strcpy (arqdst, argv [ 2 ] );
47
nome1 = fopen ( arqorg, "rb"); "rb"); nome2 = fopen ( arqdst,"wb"); arqdst,"wb"); if (nome1 == NULL | | nome2 == NULL) { printf(" \nErro na abertura dos arquivos.\n"); exit ( 1 ); } whil wh ilee (fge (fgets ts (buf (buffe fer, r, 512 512,, nome nome1) 1) ) fprin fprintf tf (nom (nome2 e2,, buffe buffer) r);; fclose (nome1); fclose(nome2);
} 19.3. Principais Principais funções para para leitura leitura e gravação direta direta (arquivos (arquivos tipo binário) binário) Normalmente, para acesso direto se abre o arquivo como binário, para que a correspondência correspondência de caracteres seja de 1 para 1.
Funções para posicionamento: •
rewind: coloca o ponteiro interno de IO no início do arquivo dado por fp. void rewind (FILE *); rewind ( fp );
fseek – move o ponteiro interno de IO do arquivo dado por fp conforme offset e origem. O parâmetro offset indica o número de bytes, a partir da origem origem, que o ponteiro deve se deslocar. Os valores possíveis para origem são: •
0 ou SEEK_SET → início do arquivo 1 ou SEEK_CUR → posição atual do ponteiro 2 ou SEEK_END → final do arquivo int fseek (FILE *, long long int, int); x = fseek (fp, offset, origem); // Note que a variável offset é do tipo long int. // Por exemplo, a instrução fseek (fp, 0l, 0) é equivalente a rewind (fp). // A função fseek retorna zero (0) para sucesso e um valor diferente de zero (0) para erro. •
fread : lê para buf nblocos de tam bytes do arquivo dado por fp. int fread (void *, *, int, int, FILE *); x = fread (buf, tam, nblocos, fp); // A função fread retorna o número de blocos lidos.
•
fwrite: funciona como fread, só que para gravação. A função retorna o número de blocos que foram gravados. int fwrite (void *, int, int, FILE *); x = int fwrite (buf, tam, nblocos, fp);
// Exemplo: gravar e ler a variável double x de um arquivo. ... double x; ... fwrite (&x, sizeof (double), 1, fp); 48
... fread (&x, sizeof (double), 1, fp); •
a tual (em bytes) do ponteiro do arquivo em em relação à origem. ftell: retorna a posição atual long ftell ( FILE *); y = ftell ( fp );
// Exemplo: Fazer um programa inicie um vetor de de 100 elementos elementos com os números de de 0 a 99, // o grave grave em um arquivo arquivo e o leia leia para para outro outro vetor. vetor. # include # include void main ( ) { FILE *fp; int i; float v1[100], v2[100], v2[100], *pv; for (pv = v1, i = 0; i < 100; i++ i++) (*pv)++ = (float) i; if ((fp = fopen("teste.dat", "wb")) == NULL) { prin printf tf(" ("\n \nE Erro rro de de abe abert rtur ura: a: gr gravaç avação ão") ");; exit ( 1 ); } fwrite(v1, sizeof(float), 100, fp); fclose(fp);
}
if ( ( fp = fopen ("teste.dat", "rb")) == NULL) { prin printf tf(" (" \n Erro rro de de ab abertu erturra: le leitur itura" a")); exit ( 2 ); } fread fread ( v2, v2, sizeof sizeof (float) (float),, 100 100,, fp); fp); fclose ( fp ); for (pv = v2, v2, i = 0; 0; i < 100; 100; i++) i++) printf printf (" (" %.2f %.2f\n" \n",, (*PV (*PV)++ )++); );
// inicia icia o vetor // abre o arquivo
// grava vetor // fecha o arquivo // reabre o arquivo teste
// lê para para nov novoo vetor vetor // fecha o arquivo/ // impri imprime me vetor vetor lido lido
/* Exemplo: Fazer Fazer um programa que grave em um arquivo três vetores de de 100 elementos cada, sendo o primeiro formado pelos números de 0 a 99, o segundo os 100 primeiros números pares e o terceiro terceiro os 100 primeiros múltiplos de de 3. A seguir fechar o arquivo e reab reabri ri-l -loo lend lendoo e impr imprimi imind ndoo cada cada um dos dos vet vetor ores es.. */ # include #i nclude # define TAM 100 void main ( ) { FILE *fp; int i; float v1[TAM], v1[TAM], *pv; if ((f ((fpp = fope fopenn ("t ("tes este te.v .vet et", ", "wb" "wb")) )) == NU NULL LL)) // Ab Abre re arqu arquiv ivoo tes testan tando do se houv houvee err erro. o. { prin printf tf(" (" \n Err Erro ao ao abr abrir ir arqu arquiv ivoo inic inicia ial. l.\n \n") ");; exit(1); } for (pv = v1, i = 0; i < TAM; i++) *pv++ = (float)i; // Ge G era números de 0 a 99 // Grava Grava apena apenass um bloco bloco de de taman tamanho ho v1, o que equivale a gravar sizeof (float) x TAM // Test Testaa se grav gravou ou tud tudo. o. if (fwrite(v1, sizeof(v1), 1, fp) != 1) { prin printf tf (" \n Err Erro ao ao gr gravar avar vetor tor 1.\ 1.\nn"); "); exit ( 2 ); 49
} for (pv = v1, i = 0; i < TAM; i++) (*pv)++ = (float) i * 2;
// vet = 0,2,4,...,198
// Grava TAM blocos com dimensão float, o que equivale a gravar sizeof (float) x TAM // Testa se gravou tudo. if (fwrite(v1, sizeof(float), TAM, fp) != TAM) { printf (" \n Erro ao gravar vetor 2.\n"); exit ( 3 ); } for (pv = v1, i = 0; i < TAM; i++) *pv++ *pv ++ = (float) (float) i * 3; /* vet: vet: 0,3,6,.. 0,3,6,...,29 .,2977 */ // Grava TAM TAM blocos com dimensão float, o que equivale a gravar sizeof (float) x TAM // E tes testa ta se se gra gravo vouu tudo tudo.. if (fwrite(v1, sizeof(float), TAM, fp) != TAM ) { prin printf tf ("\n ("\nE Erro rro ao ao gr gravar avar vetor tor 3.\ 3.\nn"); "); exit ( 4 ); }; fclose ( fp );
// Fe Fecha o arquivo/
// Reabre arquivo arquivo testando se houve erro. if ((fp = fopen("teste.vet", "rb")) == NULL) { prin printf tf(" (" \n Err Erro ao reab reabri rirr o arqu arquiv ivo. o.\n \n") ");; exit ( 5 ); } fread(v1, sizeof(v1), 1, fp); for (pv = v1, i = 0; i < TAM; i++) printf("%f ", *pv++); printf ("\n\n"); rewind (fp);
// Lê o primeiro vetor // Imprime primeiro vetor // Pula 2 linhas // Volta ao início arquivo
// A part partir ir do inic inicio io e com com des deslo loca came ment ntoo v1, aponta para o segundo vetor. fseek (fp, (long) sizeof (v1), 0); fread (v1, sizeof (float), TAM, fp); for (pv = v1, i = 0; i < TAM; i++) printf("%f ", *pv++); printf ("\n\n"); rewind (fp);
// Lê o segundo vetor // Imprime segundo vetor // Pu P ula 2 linhas // Volta ao início arquivo
// A partir do início e com deslocamento de 2 x v1, aponta para o terceiro vetor. fseek (fp, (long) sizeof (v1) * 2,0); fread (v1, sizeof (v1), 1, fp); // Lê o terceiro vetor for (pv=v1, i=0; i
50
Exemplo do uso de estruturas em arquivos: ar quivos: struct s_prop { char nome[20]; double mod; double coef; }; typedef struct s_prop sprop; sprop prop; sprop variasprops[100]; ... // Grav Gravaa uma uma prop propri ried edad adee fwrite (&prop, sizeof(sprop), 1, fp); •
// Grava um elemento da estrutura
// Grava Grava vetor vetor com com várias várias propr propried iedade adess fwrite(variasprops, sizeof(sprop), 100, fp);
REFERÊNCIAIS REFERÊNCIA IS BIBLIOGRÁFICAS 51
1. ZWARCFITER, J.M. & MARKENZON, L.. Estruturas de Dados e Seus Algoritmos . Ed. LTC Rio de Janeiro, 1994. 2. TENENBAUM, A.et alk. Estruturas de Dados Usando C . Ed. Makron Books, S~saao Paulo, 2001. 3. Furtado, A. et et al – Estruturas de Dados . Ed. Campus. Rio de Janeiro, 1985. 4. AZEREDO, P.A. – Métodos de Classificação de Dados. Ed. Campus. Rio de Janeiro, 1996. 4.
O'BRIEN, S. – C Completo e Total. Makron Books do Brasil, São Paulo 1992. 5. ASCENCIO, A. – Estruturas de Dados em DELPHI. Ed. Pearson / Prentice Hall, São Paulo, 2005. 6. PUGA, S. & RISSETTI, G. – Lógica de Programação e Estruturas de Dados. Ed. Pearson /
Prentice Hall, São Paulo, 2005. 7. PUGA, S. & RISSETTI, G. – Lógica de Programação e Estruturas de Dados Com Aplicações em
Sã o Paulo, 2005. Java. Ed. Pearson / Prentice Hall, São
52
E X E R C Í C I O S A D I C I O N A I S
Cadeias de de Caracteres Caracteres - Strings 1)
Escreva um programa que receba, através do teclado, 5 (cinco) cadeias de até 20 caracteres e as armazene em um array unidimens unidimensional ional – vetor – de dimensão 5 (cinco). Após o programa deverá pesquisar os caracteres de cada elemento do vetor e, onde encontrar uma consoante b substituí-la pelo caracter 0 (zero), e onde encontrar um caractere consoante diferente de b substituí-la pelo caractere 1 (um). 53
As substituições devem ocorrer na própria cadeia, na posição original onde as respectivas consoantes porventura forem encontradas. Neste estágio do algoritmo as vogais não devem ser manipuladas. Após, o programa deverá pesquisar novamente o vetor e, para cada elemento do vetor: a) Visuali Visualizar zar a quanti quantidad dadee de vogais a , e , i , o e u que forem encontradas ; b) Visualizar Visualizar a quantidade quantidade de conjun conjunto to de vogais vogais ae , ai , ao e au que forem encontradas ; c) Apagar todas todas as ocorrência ocorrênciass consecutiv consecutivas as da cadeia cadeia ua ; d) Substituir todas ocorrências de duas vogais vogais consecutivas pela cadeia xx ; e) Indicar todas todas as posições posições relativas das das possíveis possíveis ocorrências ocorrências da cadeia ea ; e f) Inserir Inserir seu nome, nome, em formato formato minúsculo, minúsculo, a partir da quarta quarta posição de cada cada cadeia ; g) Visualizar, em formato formato maiúsculo, todas as vogais presentes presentes nas cadeias cadeias do vetor vetor ; h) Sempre que que possível, concatenar concatenar seu primeiro sobrenome sobrenome em cada cadeia do vetor vetor ; e i ) Visualizar a quantidade de caracter em cada cadeia do vetor. 2) Escreva um programa que receba 1 (um) valor inteiro, 1 (um) caracter alfabético – forçosamente em formato minúsculo – e 3 (três) cadeias de 10 (dez) caracteres – também forçosamente em formato minúsculo – através do teclado e, após: a) Transforme Transforme o valor valor inteiro inteiro digitado digitado em uma cadeia cadeia e o visualize visualize ; b) Visualize Visualize o caracter caracter alfabético alfabético em sua forma forma maiúscu maiúscula la ; c) Concatene Concatene as 2 primeiras primeiras cadeias cadeias em uma uma única cadeia cadeia de 20 caractere caracteres, s, e a visualize visualize ; d) Visualize Visualize a cadeia resultan resultante te do processado processado no no item 3 (três) (três) em formato formato maiúsculo maiúsculo ; e)
Execute a geração de uma 4a cadeia cadeia que deve ser resultante resultante da extração de 5 caracteres caracteres da cadeia o gerada no item 4, a partir de seu 12 (décimo segundo) caracter ;
f)
Extraia 4 (quatro) caracteres da cadeia gerada no item 5 (cinco), a partir de seu 8o (oitavo), e a visualize após a extração ;
g)
Execute a inserção da 3a (terceira) cadeia digitada, na 2a (segunda) cadeia digitada, a partir de seu 5o (quinto) caracter;
h) Visualize Visualize a quantidad quantidadee atual de caracte caracteres res das das cadeias cadeias geradas geradas até o momento momento ; e i)
Informe, se for o caso, a posição do primeiro caracter da subcadeia aba na cadeia 1.
Registros - Structures 3)
Escreva um programa que preencha, a partir do teclado, duas estruturas distintas do tipo vetor com os nota 10) dos nome nomess e as notas notas (as (as notas notas têm têm de estar estar cont contid idas as no inte interv rvalo alo 0 dos alun alunos os,, respectivamente, respectivamente, de uma turma de 100 alunos. Após, exteriorize somente os nomes dos alunos que obtiveram notas iguais ou maiores que 5 (cinco). 54
4) Escreva Escreva um programa programa que preencha, preencha, a partir do teclado, duas estrutur estruturas as distintas do tipo vetor com as idades de 100 pessoas. A primeira estrutura do tipo vetor deverá receber somente as idades das pessoas do sexo masculino, enquanto a segunda deverá armazenar as idades das pessoas do sexo feminino. Após, o programa deverá exteriorizar os nomes, o sexo e as idades das pessoas que possuem idade compreendida compreendida entre 20 (vinte) e 40 (quarenta) anos, inclusive. 5)
Escreva um algoritmo que preencha 3 (três) estruturas do tipo registro com os nomes e as idades de 3 (três) pessoas – cada conjunto de informações sobre uma pessoa deverá ser conteúdo de um registro – e, i dade. após, visualize o nome da(s) pessoa(s) de mais idade.
4)
Escreva um algoritmo que preencha uma estrutura do tipo vetor de registros, de dimensão igual a 100 (cem), onde cada registro deve conter o nome e a idade de uma pessoa, informados através do teclado e que, após, visualize o nome da pessoa de menor idade e o nome da pessoa de mais idade.
5)
Escreva um algoritmo que preencha uma estrutura do tipo vetor de registros, onde cada elemento deverá armazenar o nome, a idade e os 5 graus (notas) obtidos em 5 (cinco) verificações de aprendizagem, de uma turma de 90 (noventa) alunos. Após o programa deverá visualizar os nomes de todos os alunos da turma acompanhados de sua situação acadêmica – aprovado ou reprovado. A situação de aprovado somente pode ser computada se o aluno obtiver todos os seus graus maiores ou iguais a 5 (cinco). Caso contrário, ele deverá ser assinalado como reprovado.
6)
Escre Escreva va um algorit algoritmo mo que que preen preencha cha uma uma estrut estrutura ura do tipo tipo vetor vetor de regist registros ros,, de dime dimens nsão1 ão100 00 (cem) (cem),, onde cada registro deve armazenar o nome e a idade de uma pessoa e que, após, os nomes dos alunos de menor e maior idades, respectivamente. respectivamente. Escreva um algoritmo que preencha duas estruturas homogêneas de dados, a saber:
7) a)
Um vetor de registros, onde cada elemento deve armazenar armazenar código e nome de uma disciplina ; e
b)
Uma certa matriz de regist registros ros,, onde onde cada cada linha represen representa ta uma disciplina, disciplina, den dentre tre aquelas aquelas explicitadas explicitadas no vetor, e onde deverão ser armazenadas (em cada elemento da linha) a matrícula, o nome e os 3 (três) graus (notas) obtidos em suas verificações de aprendizagem.
A turma possui 10 (dez) alunos que cursam, cada um, obrigatoriamente, 5 (cinco) disciplinas. Após, o algoritmo deverá visualizar os nomes de todos os alunos da turma, acompanhados de sua situação acadêmica – aprovado ou reprovado – e, se o aluno estiver reprovado, qual(is) a(s) disciplina(s) que o colocaram em tal situação. A situação de aprovado somente pode ser computada se o aluno obtiver todos os seus graus maiores ou iguais a 5 (cinco). Caso contrário, ele deverá ser assinalado como reprovado. 10) Escreva um programa que preencha, com dados fornecidos através do teclado: a)
Dois vetor vetores es de dimen dimensão são 50 com com valores valores inteiros inteiros na na faixa de 1 a 50, que serv servirão irão como como índices índices para para as linhas e colunas, respectivamente, de uma certa matriz; e
b) Uma matriz matriz quadrad quadradaa supramencio supramencionada, nada, de ordem ordem 50, com com valores valores reais reais maiores maiores que Zero; Zero; No entanto, o programa só deverá preencher as posições da matriz (linha x coluna) que tiverem como índices os conteúdos do 1o vetor (índices para as linhas) e do 2o vetor (índices para as colunas). Todas as outras posições da matriz deverão estar preenchidas com Zeros Abaixo é apresentada uma representação gráfica do quanto solicitado: 55
vet_col 1
2
1
vet_lin
1
1 2 3 4 5 6 7
2 4 5 37 45 50 0
1 2 3 4 5
48 49 50
0 0 0
3
3
2
4
4
22
40 40
7
46 46
49
0
0
50
0
x
0 0 0 0
0
x
0
0
0
x
0
0
0
0
0
0
0
0
x
0
0
0
0
0
0
0
0
x
0
0 0 0
0 0 0 0 0
37
0
45 50
x
4
6
22 0 0 0 0 0
0
3 0 0 0
5
56
40 0 0 0 0 0
46 0 0 0 0 0
50 0 0 0 0 0