Buscar

Programação I - Apostila sobre toda a cadeira

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 235 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 235 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 235 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

1
PROGRAMAÇÃO DE COMPUTADORES
Prof. Marilton Sanchotene de Aguiar
Computação / CDTEC / UFPEL
Versão 2013/1
2
SUMÁRIO
— Considerações Iniciais (slide 3)
— Conceitos Básicos (slide 8)
— Estruturas de Repetição (slide 52)
— Matrizes (slide 69)
— Ponteiros (slide 90)
— Funções (slide 114)
— Estruturas (slide 149)
— Arquivos (slide 179)
— Alocação Dinâmica (slide 206)
— Listas Encadeadas (slide 222)
3
CONSIDERAÇÕES INICIAIS
A tarefa de programar
— É uma tarefa intelectual
— Envolve:
— Traduzir especificações em código
— Analisar código escrito por outros programadores
— Modificar código para remover defeitos
— Manipulação direta de textos escritos em linguagens de 
programação (linguagens não-naturais ou não-amigáveis)
— O desconhecimento dos recursos da linguagem e de técnicas de 
codificação aumenta o esforço da programação
Técnicas de codi$cação
— Envolvem a escrita e organização (separação em módulos, 
endentação, etc) de textos carregados de símbolos
— Inclusão de informações necessárias a futuras atividades de 
manutenção (comentários)
— Inclusão de dispositivos de segurança no código 
Diretrizes genéricas
— São recomendações genéricas aplicáveis a muitas linguagens de 
programação
— As diretrizes abordam:
— Dados
— Nomes
— Estrutura de controle
— Leiaute
— Comentários
Tratamento de erros
— Programação defensiva: tudo pode vir a dar errado
— Testar erros nas entradas e tentar se comportar bem quando os 
encontra
— Aumentar o número de verificações no código
— Validar entrada de dados via interface do usuário
— Validar dados fornecidos de uma rotina a outra
— Consistência em estruturas de dados
8
CONCEITOS BÁSICOS
9
Introdução
— Criada por Denis Ritchie em 1972 (Bell Labs, USA)
— Sua primeira utilização importante foi a escrita do S.O. Unix
— Em meados de 1970 ela foi liberada para uso em Universidades
— Em 1980 já existiam várias versões de compiladores de diversas 
empresas (não restritos ao ambiente Unix)
— C é uma linguagem de propósito geral, adequada à programação 
estruturada
— Juntamente com Fortran, é a principal linguagem para uso científico 
(compiladores, analisadores léxicos, bancos de dados, editores de 
texto...)
10
Principais Caracterís(cas
— Portabilidade
— Modularidade
— Compilação separada
— Recursos de baixo nível (tratamento de caracteres)
— Geração de código eficiente
— Confiabilidade
— Regularidade
— Simplicidade
— Facilidade de uso
11
Sintaxe
— São as regras para cada construção válida em uma linguagem 
específica. Estão relacionadas com:
— Tipos: definem as propriedades dos dados
— Declarações: expressam as partes de um programa
— Funções: especificam as ações que um programa executa, quando 
roda
— Determinação e alteração de valores
— Chamada de funções de I/O
12
Funções
— São os blocos básicos dos programas em C
— Há funções básicas, definidas na biblioteca C:
printf( ), scanf( ), getchar( ), putchar( )
— Funções podem ser definidas pelo programador
— Todo programa C inicia sua execução chamando a função main( ), 
sendo obrigatório a sua declaração no programa principal.
13
EX
EM
P
LO
#include <stdio.h>
/* comentario */
//comentario
main( ) {
 printf("oi");
}
14
Iden($cadores
— São os nomes usados para fazer referência a
— Variáveis
— Funções
— Módulos
— Rótulos
— Demais objetos definidos pelo usuário
15
Iden($cadores (cont)
— Regras de Formação:
— O primeiro caracter deve ser uma letra ou sublinhado
— Os 32 primeiros caracteres são significativos
— Case sensitive - difere maiúsculas de minúscula
— Exemplos de identificadores válidos em C:
— a
— A
— Nota
— nota
— _nota
Diretrizes para as Variáveis
— Declarar sempre todas as variáveis
— As declarações devem ser acompanhadas de comentários descritivos
— Cada declaração deve ocupar uma linha
— Declaração próximo do uso (sempre que possível)
— Os tipos e nomes das variáveis devem ser alinhados em colunas
— Inicializar todas as variáveis em sua declaração
— Documentar porque da inicialização com um dado valor, se não for 
óbvio
Variáveis: Escopo
— Minimizar o escopo das variáveis
— Preferir variáveis locais a uma rotina do que locais a um módulo, 
que são preferíveis a variáveis globais
— Minimizar o uso de variáveis globais. 
— Variáveis globais causam problemas: dificulta reuso, quebra de 
modularidade, etc.
— Usar variáveis globais somente para:
— Preservação de valores globais ao programa inteiro
— Simulação de constantes com nome
— Dados de uso extremamente comum
— Dados que são passados a rotinas de nível profundo sem serem manipulados por rotinas de nível 
intermediário
Variáveis: Finalidade
— Usar cada variável com uma única finalidade
— Não reutilizar nomes com propósitos diferentes
— Evitar variáveis com dois significados
— Conferir se todas as variáveis declaradas são usadas
Variáveis: Nomes
— Todos os nomes devem descrever de forma completa e precisa a 
entidade que representam
— Usar nomes auto-explicativos (auto-documentáveis) para as 
variáveis, rotinas e todos os tipos de elementos da linguagem
— Os próprios nomes contém informação sobre o funcionamento do 
código 
— Usar nomes mais próximos do problema do que da 
implementação
Nomes: Exemplo
int x, y, z, x1, x2;
— Problemas de compreensão causados:
— É impossível a outro programador deduzir o propósito de cada 
variável
— Mesmo o programador que escreveu o código pode ter 
problemas para entendê-lo após alguns dias
— A atividade de debug torna-se mais difícil
Declaração
— Todos os identificadores devem representar palavras ou frases do 
idioma utilizado
— Código para distribuição internacional: usar inglês
— Se for usado português, considere:
— Usar nomes de funções no infinitivo, imperativo ou indicativo 
presente 
— Não omitir preposições
Declaração
— Evitar abreviações
— Abreviações devem ser usadas quando as linguagens não 
permitem nomes longos
— Os nomes devem ser pronunciáveis
— Os nomes devem diferenciáveis pelo seus primeiros caracteres
— Evitar diferenciar por numeração (ex: temp, temp2)
— Evitar a ocorrência de identificadores com nomes que possam ser 
confundidos
Diretrizes de denominação
— Índices: usar os tradicionais i, j, k apenas em casos simples. Prefira 
nomes mais significativos (ex: contadorDeRegistros)
— Variáveis de Status: prefira nomes que indiquem o significado (ex: 
dadoPronto, tipoDeRelatório)
— Variáveis Temporárias: nomes com significado. Evitar o uso de 
temp
— Variáveis booleanas: usar nomes significativos como feito, erro, 
achou, sucesso. 
— Evitar nomes que não indiquem valor lógico ou nomes negativos 
(ex: nãoAchou)
Diretrizes de denominação
— Tipos enumerados: usar prefixos comuns para nomes 
pertencentes ao mesmo grupo (corAzul, corVermelha, corVerde)
— Constantes: usar nomes indicativos de significado da constante (ex: 
totalDeCiclos)
25
Tipos
— O Tipo serve (grosso modo) para determinar
— Como os valores serão armazenados
— Quais operações poderão ser realizadas sobre estes valores
— Tipos para Dados e para Funções
— Tipos escalares
— Tipos não-escalares
— tipo de estrutura, tipo de união, tipo de matriz
26
Tipos Escalares
— Tipos Aritméticos
— Tipos Inteiros
— char, signed char, unsigned char, short, unsigned short, int, unsigned 
int, long, unsigned long
— Tipos Flutuantes
— float, double, long double
— Tipos Ponteiros
— para funções
— para objetos de dados
— para tipos incompletos
27
Tipos Inteiros
Tipo Intervalo
char [0,128)
signed char (-128,+128)
unsigned char (0,256)
short (-215,215)unsigned short [0, 216)
int (-215,215)
unsigned int [0,216)
long (-231,231)
unsigned long [0,232)
28
Tipo Flutuante
Tipo Intervalo
float (3.4-38,215)
double (1.7-308,1.7308)
long double (3.4-4932,3.44932)
Diretrizes para (pos numéricos
— Evitar os chamados números mágicos, usando constantes no lugar 
de literais (exceto no caso de 0, 1)
— Usar constantes ao invés de valores explícitos no código
#define Pi 3.141592
— Verificar se o valor dos divisores não pode ser 0
— Explicitar todas as conversões de tipo
Diretrizes para (pos numéricos
— Inteiros
— Tratar a possibilidade de truncamento
— Tratar a possibilidade de estouro (overflow), inclusive em 
resultados intermediários
— Ponto-flutuante
— Evitar somas e subtrações de números de magnitude muito 
diferentes
— Tratar possibilidades de overflow e underflow 
— Tratar possibilidades de erro de arredondamento
31
EX
EM
P
LO
#include <stdio.h>
//tamanho dos tipos
main( ) {
char c;
unsigned char uc;
int i;
unsigned int ui;
float f;
double d;
printf("char %d\n", sizeof(c));
printf("unsigned char %d\n", sizeof(uc));
printf("int %d\n", sizeof(i));
printf("unsigned int %d\n", sizeof(ui));
prinft("float %d\n", sizeof(f));
printf("double %d", sizeof(d));
}
32
Operadores
— Atribuição (=)
— Aritméticos (+, -, *, /, %)
— Outros operadores
— i += 2; (equivalente: i = i+2;)
— x *= y+1; (equivalente: x = x*(y+1);)
— d -= 3; (equivalente: d = d-3;)
33
Operadores (cont)
— Relacionais:
— >, >=, <, <=, ==, !=
— Lógicos:
— && (and), || (or), ! (not).
Em C, falso é 0 (zero); qualquer outro valor é
considerado verdadeiro (inclusive negativo)
Operadores relacionais e lógicos têm
menor precedência do que operadores aritméticos
34
{De,In}cremento
— ++x (incrementa x antes de usar o seu valor)
— x++ (incrementa x depois de ser usado)
— --y (decrementa y antes de usar o seu valor)
— y-- (decrementa y depois de ser usado)
35
 11000001
& 01111111
 
 01000001
 10000000
| 00000011
 
 10000011
 01111111
^ 01111000
 
 00000111
Operador Ação
& AND
| OR
^ XOR
~ Complemento
<< Deslocamento a esquerda
>> Deslocamento a direita
Operadores Bit a Bit
36
EX
EM
P
LO
#include <stdio.h>
main () {
 unsigned char x;
 x = 7;
 printf ("%d", x);
 x = x << 1;
 printf ("\n%d", x);
 x = x << 3;
 printf ("\n%d", x);
 x = x << 2;
 printf ("\n%d", x);
 x = x >> 1;
 printf ("\n%d", x);
 x = x >> 2;
 printf ("\n%d", x);
 x = ~x;
 printf ("\n%d", x);
}
Saída:
7 (00000111)
14 (00001110)
112 (01110000)
192 (11000000)
96 (01100000)
24 (00011000)
231 (11100111)
x = x << 1; (multiplica x por 2)
x = x >> 1; (divide x por 2)
37
Precedência
( ) [ ] ->
! ~ ++ -- - ((po) *
& sizeof
* / %
+ -
<< >>
< <= > >=
== !=
&^!
&&
||
?:
= += -= *= /= etc
,
Maior
Menor
38
Funções Básicas – prinH()
— Sintaxe: 
printf("expressao de controle", argumentos);
— É uma função de E/S que permite escrever no dispositivo padrão 
(tela)
— A expressão de controle pode conter:
— caracteres que serão exibidos na tela
— códigos de formatação
— Cada argumento deve ser separado por vírgulas
39
Funções Básicas – prinH() (cont)
— Códigos de formatação:
— \n (nova linha) 
— \t (tabulação)
— \b (retrocesso)
— \" (aspas)
— \\ (barra)
— \f (salta formulário)
— \0 (nulo).
— %c (caractere)
— %d (decimal)
— %e (notação científica)
— %f (ponto flutuante)
— %o (octal)
— %s (string)
— %u (decimal sem sinal)
— %x (hexadecimal)
40
EX
EM
P
LO
S
#include <stdio.h>
main( ) {
printf("este é o numero dois: %d", 2);
}
#include <stdio.h>
main( ) {
int a, b;
float c;
a = 2;
b = 10;
c = 2/( (float) 1/a + (float) 1/b);
printf("a= %d b= %d\n", a, b );
printf("a média harmônica de a e b é: %f", c);
}
41
Funções Básicas – scanf()
— Sintaxe:
scanf("expressao de controle", argumentos);
— É uma função de E/S que permite ler dados formatados da entrada 
padrão (teclado)
— A lista de argumentos deve consistir dos endereços das variáveis na 
memória do computador.
— Como obter o endereço de uma variável??
— Colocando um & junto ao nome da variável.
— Ex.: &a (fornece o endereço da variável a)
42
EX
EM
P
LO
#include <stdio.h>
main( )
{
int a, b;
float c;
printf("entre com o valor de a\n");
scanf("%d", &a);
printf("entre com o valor de b\n");
scanf("%d", &b);
c = 2/((float) 1/a + (float) 1/b);
printf("a=%d b=%d\n", a, b );
printf("a média harmônica de a e b é: %f", c);
}
43
Estruturas de Controle – if()
— Sintaxe: 
if (condição) comando1;
else comando2;
— Se condição for verdadeira (qualquer 
valor diferente de zero), o programa 
executará o comando1; caso 
contrário (condição for falsa), o 
programa executará o comando2.
— No lugar de um comando, pode haver 
uma sequência de comandos (ou seja, 
um bloco).
— Em C, um bloco incia com um abre 
chaves e termina com um fecha 
chaves:
if (condição) {
comando1;
comando2;
comando3;
...
} else {
comando4;
comando5;
...
}
44
EX
EM
P
LO
#include <stdio.h>
main( )
{
 int a, b;
 printf("digite dois numeros\n");
 scanf("%d %d", &a, &b );
 if(b)
 printf("%d\n", a/b );
 else
 printf("nao pode dividir por zero");
}
45
Estruturas de Controle – switch()
— Sintaxe:
switch(expressao)
{
 case constante1:
 sequencia_de_comandos1;
 break;
 case constante2:
 sequencia_de_comandos2;
 break;
 case constante3:
 sequencia_de_comandos3;
 break;
 ...
 default:
 break;
}
Diretrizes para Estruturas de controle
— Quando existe uma sequência correta de execução das instruções 
esta deve ser facilmente reconhecível
— O código deve ser lido de forma que possa ser lido de cima para 
baixo (não usar goto)
— Instruções correlatas devem ser agrupadas e grupos devem ser 
separados por linhas em branco 
Diretrizes para Estruturas de controle (cont.)
— IF simples
— Escrever primeiro o caso normal, e depois as exceções
— Evitar cláusulas vazias de IF 
— Quando não houver cláusula ELSE, documentar o porquê não é 
necessária
Diretrizes para Estruturas de controle (cont.)
— Cadeias de IF: Não usar o último ELSE da cadeira para tratar um 
caso restante, reservá-lo para tratar condições de exceção
— Simplificar testes complicados por meio de chamadas a funções 
booleanas
— Verificar se todos os casos são cobertos
Diretrizes para Estruturas de controle (cont.)
— Usar seleção múltipla (case/switch) quando a linguagem permitir
— Ao usar seleções múltiplas, classificar os casos por ordem 
alfabética/numérica ou por freqüência de ocorrência, mantendo 
entretanto juntos os casos cujo tratamento usa o mesmo código
Diretrizes para Estruturas de controle (cont.)
— Simplificar as expressões de teste usadas
— Partir os testes introduzindo variáveis booleanas
— Usar parênteses
— Usar regras de De Morgan (ex: !(A || B) == !A && !B)
— Minimizar os níveis de aninhamento
— Retestar condições quando isso reduz aninhamento
— Converter conjunto de if aninhados em cadeias de if ou em seleção 
múltipla
— Passar código profundamente aninhado para rotina independente
51
EX
ER
C
ÍC
IO
S
1) Fazer um programa que lê as 3 notas de um aluno de 
Programação I (v1, v2 e MT, onde MT é a média dos trabalhos). 
O programa calcula e imprime a média do aluno, usando a 
fórmula Média=(3*v1+3*v2+4*MT)/10.
2) Utilizando o programa anterior, fazer um novo programa que 
verifica se o aluno atingiu a média 7. Caso positivo, o programa 
imprime a mensagem "aprovado por média". Caso contrário, o 
programacalcula e imprime o valor necessário na optativa, 
apresentando a mensagem apropriada. (Lembre-se que a média 
dos trabalhos não pode ser substituída pela optativa).
52
ESTRUTURAS DE REPETIÇÃO
53
Comandos de Iteração – for()
— Sintaxe:
— Caso 1
for( inicializacoes; testes; atualizacoes)
 comando;
— Caso 2
for( inicializacoes; testes; atualizacoes)
{
 comando1;
 comando2;
 comando3;
 …
}
54
EX
EM
P
LO
#include <stdio.h>
main( ) {
int i, n;
float valor, media;
media = 0;
printf("entre com o numero de valores\n");
scanf("%d", &n );
for( i=0; i<n; i++ ) {
 printf("entre com o %d valor\n", i+1 );
 scanf("%f", &valor);
 media+=valor;
}
media/=n;
printf("A media destes valores eh:%f\n", media);
}
55
for() in$nito
…
char ch;
ch='\0';
for( ; ; ) {
 ch = getchar(); 
 if(ch=='A')
 break; 
}
printf("tu digitaste um A, tche!\n");
…
56
Comandos de Iteração – for() (cont)
— Laços for sem corpo:
for( i=0 ; i<tam ; i++ );
— Este trecho serve, por exemplo, para posicionar um indexador (i, 
neste caso) numa dada posição, que pode ser o final de um vetor.
— Repare no ponto-e-vírgula logo após o parêntesis.
— Este ponto-e-vírgula configura-se como um erro bastante frequente 
na programação, pois encerra o escopo do for() naquele momento, 
desconsiderando a aplicação iterada do bloco de instruções que o 
segue.
57
Comandos de Iteração – while()
— Sintaxe:
— Caso 1
while( condicao )
 comando;
— Caso 2
while( condicao ) {
 comando1;
 comando2;
 comando3;
 …
}
58
Comandos de Iteração – while() (cont)
— Exemplo:
int i = 0;
while ( i <= 100) {
 printf("%d\n", i);
 i++;
}
— Primeiro faz a comparação de i depois executa o laço de comandos
— Repare na linha i++ incrementando o valor de i
59
Comandos de Iteração – do...while()
— Sintaxe:
— Caso 1
do
 comando;
while( condicao );
— Caso 2
do {
 comando1;
 comando2;
 comando3;
 …
} while( condicao );
60
Comandos de Iteração – do...while() (cont)
Exemplo:
do
 scanf("%d", &num);
while( num > 100 );
Este trecho de código lê números do teclado até que encontre um 
número menor ou igual a 100.
61
EX
EM
P
LO
#include <stdio.h>
void main(void) {
 unsigned int i;
 int j;
 
 i=1;
 for (j=0; j<4; j++) {
 i = i << 1;
 printf("%d : %d\n", j, i);
 }
 
 for (j=0; j<4; j++) {
 i = i >> 1;
 printf("%d : %d\n", j, i);
 }
}
62
Comandos de desvio – break
— Usos:
— Terminar um case do comando switch;
— Forçar uma terminação imediata de um laço.
— Quando o comando break é encontrado dentro de um laço, o laço é imediatamente 
terminado e o controle do programa retorna no comando seguinte ao laço.
— Forma Geral:
for( i=0; i<100; i++ ) {
 printf("%d", i);
 if( i == 10 )
 break;
}
printf("Valor de i ao sair do laco: %d",i);
63
Comandos de desvio – exit
— Da mesma forma que se pode sair de um laço, pode-se sair de um programa 
usando a função exit() da biblioteca padrão (stdlib.h).
— Esta função provoca uma terminação imediata do programa inteiro, forçando 
um retorno ao sistema operacional.
— Forma Geral:
void exit(int codigo_de_retorno);
— O valor de codigo_de_retorno é retornado ao processo chamador, que é 
normalmente o sistema operacional
— O zero é geralmente usado como código de retorno que indica uma terminação 
normal do programa. Outros valores são usados para indicar algum tipo de 
erro.
Diretrizes para as estruturas de repe(ção
— Estruturas se diferem pelo teste de finalização:
— No início: while
— No final: do...while
— No meio: 
while (true) {
<instr>; 
if (<cond>) break; 
<instr>;
} 
Diretrizes para as estruturas de repe(ção (cont.)
— Laços do tipo FOR devem ser usadas quando se sabe que o laço deverá ser executado um 
número específico de vezes.
— A condição de saída deve ser facilmente identificável 
— Usar um formato padronizado e facilmente reconhecível para laços eternos
while (true) { <instrucoes>}
— Cada laço deve executar apenas uma função (ex: não iniciar 2 vetores em um mesmo laço 
pois impede que o tamanho de um deles possa ser alterado)
— Devem ser curtos para caber em uma tela ou uma folha de listagem
— Devem usar no máximo 3 níveis de aninhamento
— Em laços grandes, deve-se redobrar o cuidado com a clareza e a documentação
66
EX
ER
C
ÍC
IO
S
1) Escreva um programa que lê as coordenadas de n pontos no 
plano cartesiano (x, y) e identifica se estes pontos pertencem: i) 
ao 1o. quadrante; ii) ao 2o. quadrante; iii) ao 3o. quadrante; iv) 
ao quarto quadrante; ou estão sobre v) o eixo dos "x"; vi) o eixo 
dos "y"; ou vii) estão na origem. Feito isso, o programa 
escreverá os totais de pontos em cada uma destas situações.
2) Considere a seguinte série 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, … e 
um inteiro positivo n. Deseja-se: i) imprimir os n primeiros 
termos da série; e, ii) calcular e imprimir a soma dos n 
primeiros termos. Desenvolva dois programas utilizando for e 
do while que resolvam este problema.
67
EX
ER
C
ÍC
IO
S
3) Dados três números inteiros correspondentes, respectivamente, 
ao dia, mês e ano de nascimento de uma pessoa e três outros 
números correspondentes ao dia, mês e ano corrente (ex. data de 
hoje), calcular e imprimir a idade em anos completos. Verificar se as 
datas são compatíveis (nascimento <= corrente).
4) Usando o comando for, faça um programa que calcule o fatorial 
de um número inteiro n. 
5) Refaça o exercício anterior usando o comando while.
6) Faça um programa que recebe um número inteiro e imprime o 
somatório de seus divisores.
68
EX
ER
C
ÍC
IO
S 7) Faça um programa que recebe um número inteiro e verifica 
se o número é primo ou não, escrevendo uma mensagem 
apropriada.
8) Faça um programa que recebe lê n conceitos de alunos (n é 
fornecido no início do programa) e conta quantos conceitos de 
cada tipo existem. Os conceitos possíveis são: A, B, C, D, E e 
podem ser fornecidos com letras maiúsculas ou minúsculas.
69
MATRIZES
70
Matrizes
— Uma matriz é uma coleção de variáveis do mesmo tipo que é referenciada 
por um nome comum
— Em C todas as matrizes consistem em posições contíguas na memória:
— o endereço mais baixo corresponde ao primeiro elemento
— o endereço mais alto corresponde ao último elemento
— Um elemento específico da matriz pode ser acessado por meio de um 
índice
— O programador deve observar os limites extremos de uma matriz
— Matrizes podem ter de uma a várias dimensões
71
Matrizes Unidimensionais
— Forma geral de se declarar uma matriz unidimensional:
tipo nome_da_variavel[tamanho];
— Como qualquer variável, as matrizes precisam ser declaradas para 
que o compilador possa alocar espaço na memória para elas
— tipo declara o tipo de base da matriz
— tamanho define a quantidade máxima de elementos que a matriz 
poderá armazenar
72
Matrizes - Exemplos
— Declaração de uma matriz chamada valor de 100 elementos do tipo int.
int valor[100];
— Para acessar o primeiro elemento da matriz valor:
valor[0]=0;
— Para acessar o último elemento da matriz valor:
valor[99]=0;
Uma matriz de N elementos tem índice que inicia em 0 (zero) e termina em N-1.
float notas[100];
double balance[20];
char linha[80];
73
Matrizes – Alocação de Memória
— Mas como o compilador calcula a quantidade de memória a ser 
alocada para uma dada matriz?
total (bytes) = sizeof (tipo) * qtde elem da matriz
— sizeof é um operador unário que, em tempo de compilação, retorna 
o tamanho em bytes da variável ou especificador de tipo entre 
parêntesis.
— O cálculo do tamanho é feito automaticamente, emtempo de 
compilação, para cada matriz declarada no programa. Não é preciso 
se preocupar com a alocação de memória.
74
Matrizes – Veri$cação dos Limites
— Atenção: a linguagem C não tem 
verificação dos limites de 
matrizes. Isto significa que se 
pode escrever valores para 
além do final da matriz, sobre 
outras variáveis ou mesmo 
sobre o próprio código do 
programa!
#include <stdio.h>
main() {
 float nota[50];
 int i;
 for( i=0; i<50; i++) {
 printf("Nota %d:\n", i+1);
 scanf("%f", &nota[i]);
 }
}
75
Matrizes – Veri$cação dos Limites
— Atenção: a linguagem C não tem 
verificação dos limites de 
matrizes. Isto significa que se 
pode escrever valores para 
além do final da matriz, sobre 
outras variáveis ou mesmo 
sobre o próprio código do 
programa!
#include <stdio.h>
main() {
 float nota[50];
 int i;
 for( i=0; i<100; i++) {
 printf("Nota %d:\n", i+1);
 scanf("%f", &nota[i]);
 }
}
76
Matrizes Bidimensionais
— C suporta matrizes multidimensionais.
— Uma matriz bidimensional é a forma mais simples
— Exemplo:
int d[10][20];
— Declara uma matriz do tipo int, com 10 linhas 20 colunas, chamada 
"d".
77
EX
EM
P
LO
#include <stdio.h>
main()
{
 float num[3][4];
 int i,j;
 for( i=0; i<3; i++)
 for( j=0; j<4; j++) {
 printf("digite o elemento da linha %d, coluna %d\n", i+1, j+1);
 scanf("%f", &num[i][j]);
 }
}
78
EX
EM
P
LO
#include <stdio.h>
#define TAM 1000
main() {
 float valor[TAM], media=0.0;
 int i,n, conta=0;
 printf("digite o numero de valores\n");
 scanf("%d", &n);
 if (( n > TAM) || ( n < 1))
 printf("erro: o tamanho deve estar entre 1 e %d\n", TAM);
 else {
 for( i = 0; i < n; i++) {
 printf("digite o %d .o valor\n", i+1);
 scanf("%f", &valor[i]);
 media+=valor[i];
 }
 media/=n;
 for( i = 0; i < n; i++)
 if( valor[i] > media )
 conta++;
 printf("media= %f \n%d valores acima da media\n", media, conta);
 }
}
79
Matrizes Mul(dimensionais
— C suporta matrizes com mais de 2 dimensões.
— O limite de dimensões é definido pelo compilador usado (alguns 
compiladores não limitam)
— Exemplo de declaração:
int m[10][20][4][100];
80
Matrizes - inicialização
— Forma Geral:
tipo matriz[tam1][tam2]…[tamN]={lista_de_valores};
— Exemplos:
int m[10]={1,2,3,4,5,6,7,8,9,10};
float aux[5]={0.0,1.0,2.0,3.0,4.0};
int matriz[10]={0};
— Os elementos são inicializados com os valores da lista, seguindo a 
ordem da esquerda para a direita. Se não houver inicializadores 
suficientes, os elementos faltantes são inicializados com 0 (zero).
81
Matrizes – inicialização (cont)
int m[100], i;
for( i=0; i<100; i++)
 m[i]=i;
float aux[1000], i;
for( i=0; i<1000; i++)
 aux[i]=0.0;
char linha[80] = { 'E','u',' ','g','o','s','t','o',' ','d','e',' ','C','\0'};
char linha[80] = { "Eu gosto de C"};
82
Matrizes de Caracteres
— Usadas para armazenar cadeias de caracteres de interesse (strings). C 
provê uma biblioteca para o tratamento de strings.
— Convenção: cada string deve terminar com o caractere especial '\0'.
— O '\0' serve para delimitar o final de uma cadeia de caracteres 
(strings).
— Com ele se pode usar as bibliotecas de tratamento de strings. Sua 
existência deve sempre ser levada em conta no tamanho de uma 
matriz de caracteres.
— Permite que se armazene uma string com número de caracteres 
menor do que o tamanho-1 da matriz.
83
EX
EM
P
LO
S
#include<stdio.h>
main() {
 char c, linha[100];
 int i=0;
 while((c=getchar()) != '\n') {
 linha[i]=c;
 i++;
 }
 linha[i]='\0'; //final de string
 printf("%s",linha);
}
#include <stdio.h>
main()
{
 char linha[100] = {"Imprima esta linha."};
 int i=0;
 while( linha[i] != '\0') {
 putchar(linha[i]);
 i++;
 }
}
84
EX
EM
P
LO
S
#include <stdio.h>
main()
{
 char s[256] = "", str[256] = "";
 scanf("%[aeiou]", s); // le apenas as vogais "aeiou"
 printf("String (s): %s\n", s);
 scanf("%[^A-Z]", str); // Nao le caracteres maiusculos de A a Z
 printf("String (str): %s\n", str);
}
#include <stdio.h>
main()
{
 char str[31];
 printf("Digite seu nome: ");
 fgets(str, 30, stdin); // e o mesmo que scanf("%30s",str); ???
 puts(str); // puts imprime na tela uma string
}
85
Matrizes de Caracteres – outros comandos
— Para utilizar os comandos abaixo deve-se incluir string.h:
strcpy(s1, s2) - Copia s2 em s1.
strcat(s1, s2) - Concatena (junta) s2 ao final de s1.
strlen(s1) - Retorna o tamanho de s1.
strcmp(s1, s2) - Retorna 0 se s1 e s2 são iguais; >0 se s1 > s2, e <0 se s1 < s2.
strchr(s1, ch) - Retorna um ponteiro para a primeira ocorrência de ch em s1.
strstr(s1, s2) - Retorna um ponteiro para a primeira ocorrência de s2 em s1.
86
EX
ER
C
ÍC
IO
S
1) Faça um programa que lê n números decimais, armazenando-os em um 
vetor. Após, o programa identifica o menor número do vetor e imprime 
sua posição.
2) Faça um programa que lê n x m valores decimais, armazenando-os em 
uma matriz com n linhas e m colunas. Após, para cada linha da matriz, o 
algoritmo calcula a média e conta quantos elementos estão acima da 
média calculada, imprimindo estas informações.
3) Fazer um programa que lê as 3 notas de n alunos (n é fornecido pelo 
usuário, no início do programa) de uma turma de Programação I (V1, V2 e 
MT, onde MT é a média dos trabalhos). O programa calcula e imprime a 
média de cada aluno, usando a fórmula M=(3*v1+3*v2+4*MT)/10. Após, o 
programa calula e imprime a média da turma em V1, em V2 e em MT. 
Finalmente, o programa conta quantos alunos obtiveram nota maior que a 
média calculada para V1, imprimindo esta informação.
87
EX
ER
C
ÍC
IO
S
4) Faça um programa que lê n números inteiros (cujo valor máximo não 
ultrapassa 1000). Após, o programa imprime em ordem crescente os números 
não duplicados do vetor.
5) Faça um programa que lê n números decimais (no máximo 10000 valores), 
armazenando-os em um vetor. Após, o programa ordena este vetor usando o 
método "Bubble Sort". Finalmente, o programa imprime o vetor ordenado.
6) Faça um programa que lê duas matrizes de números decimais, M1 e M2, ambas 
de tamanhos n x m. Após, o programa cria e imprime a matriz S, resultante da 
soma de M1 com M2.
7) Faça um programa que lê uma matriz de valores decimais e calcula a média de 
sua diagonal secundária. Após, o programa deve verificar e imprimir a posição de 
cada elemento cujo valor está abaixo da média calculada.
88
EX
ER
C
ÍC
IO
S
8) Escreva um programa que lê n coordenadas x e y de pontos e as 
armazene em uma matriz. Decida para cada ponto se está ao Norte, Sul, 
Leste, Oeste, Nordeste, Noroeste, Sudoeste, Sudeste ou sobre o ponto 
anterior e informe com uma mensagem apropriada. Para o primeiro ponto 
lido tome a origem (0,0) para sua decisão.
9) Escreva um programa que preenche um vetor de 50 posições com 
zeros, com exceção da posição central, que deve ter o valor 1. Ainda, o 
programa lê um valor n que representa o número de iterações da 
aplicação da seguinte regra:
o próximo valor da posição v[i] é (v[i-1]+v[i+1]) mod 2,
usar os valores de v[i-1] e v[i+1] da iteração anterior. 
Imprima o vetor original e todas as demais atualizações do vetor.
89
EX
ER
C
ÍC
IO
S
10) Leia um valor n ímpar (3 < n < 50) para preencher e imprimir uma matriz da 
seguinte forma:
n=5
..x..
.xxx.
xxxxx
.xxx.
..x..
11) Escreva um programa que embaralha uma matriz de ordem par n (n x n 
elementos) da seguinte maneira:
M original:
1234
2341
3412
4123
M embaralhada:
3412
4123
1234
2341
90
PONTEIROS
91
Caracterís(cas e U(lidades— Um ponteiro é o endereço de uma variável na memória.
— Uma variável de ponteiro é uma variável especialmente declarada 
para guardar um ponteiro para seu tipo especificado.
— São uma maneira rápida de referenciar uma variável em C.
— São o meio pelo qual as funções em C conseguem modificar seus 
parâmetros de chamada.
— Provêem suporte às listas encadeadas e outras estruturas de dados 
dinâmicas.
92
Operadores
— operador unário & :
— devolve o endereço da memória em que se encontra alocado seu operando;
— Exemplo:
m = &count;
— atribui a m o endereço da memória em que se encontra a variável count. Esse 
endereço não tem nenhuma relação com o valor de count.
— Pode-se imaginar & como significando "o endereço de". Desta forma, a 
sentença de atribuição anterior significa "m recebe o endereço de count".
93
EX
EM
P
LO
endereço memória
1996
2000 100 count
2004
2008
...
int count;
...
count = 100;
m = &count;
...
1) Assuma que a variável count, quando foi 
declarada, ficou alocada para a posição de memória 
2000. 
2) Assuma também que count tem como valor 100.
3) Então, após a setença de atribuição m tem o valor 
2000.
94
Operadores (cont)
— operador unário * :
— devolve o valor da variável localizada no endereço que o segue. 
(ou seja, este operador sempre interpreta seu operando como um endereço de memória!)
— a partir do exemplo anterior, se m contém o endereço da variável count:
q = *m;
— coloca o valor de count em q. 
— Agora q tem o valor 100 porque 100 está armazenado na posição 2000, endereço 
da memória em que está armazenado m.
— Pode-se pensar no * como significando "o conteúdo do endereço …". Assim, a 
sentença anterior poderia ser lida como "q recebe o conteúdo do endereço m".
95
Declarando Ponteiros
— Por exemplo, para declarar uma variável ponteiro ch para char, escreve-se:
char *ch;
— Aqui, ch não é um caractere, mas um ponteiro para caractere (são conceitos 
completamente diferentes).
— Pode-se misturar diretivas de ponteiro e de não-ponteiro na mesma 
declaração, como por exemplo:
int x, *y, count;
— Declara x e count como sendo do tipo inteiro e y como sendo um ponteiro 
para o tipo inteiro.
96
EX
EM
P
LO
S
#include <stdio.h>
void main(void)
{
 int target, source=10, *m;
 m = &source;
 target = *m;
 printf("%d", target);
}
#include <stdio.h>
void main(void)
{
 int x=0, *p1, *p2;
 p1 = &x;
 p2 = p1;
 printf("%p", p2);
}
97
Aritmé(ca de Ponteiros
— Existem apenas duas operações aritméticas que podem ser feitas 
com ponteiros:
— Adição
— Subtração
— Regras da aritmética de ponteiros:
— Cada vez que um ponteiro é incrementado, ele aponta para a 
posição de memória do próximo elemento do seu tipo base.
— Cada vez que um ponteiro é decrementado, ele aponta para a 
posição de memória do elemento anterior do seu tipo base
98
Aritmé(ca de Ponteiros (cont)
— assuma que estamos usando uma máquina na qual um inteiro ocupa 
4 bytes. Então:
int *p1, x;
p1 = &x;
p1++;
— Se x estava armazenada na posição de memória 2000. Então, após 
p1++, p1 conterá o valor 2004.
99
Comparação de Ponteiros
— É possível comparar dois ponteiros em uma expressão relacional. 
— Exemplo:
if(p<q)
 printf("p aponta para uma memoria mais baixa que q\n");
— Geralmente, comparações de ponteiros são usadas para verificar se 
dois ou mais ponteiros apontam para um mesmo objeto (uso em 
estruturas de dados tais como pilhas, filas etc)
100
Ponteiros e Matrizes
— Há uma estreita relação entre ponteiros e matrizes. De fato, os índices das 
matrizes são uma maneira mais confortável para se acessar um dado 
elemento de uma matriz.
char nome[80], *p1, ch;
p1 = nome;
— p1 foi inicializado com o endereço do primeiro elemento da matriz nome
ch = nome[4];
ou
ch=*(p1+4)
— copiam o quinto elemento de nome para ch.
101
EX
EM
P
LO
S
for( i=0; nome[i] != '\0'; i++)
 putchar(nome[i]);
for( p=nome; *p; p++)
 putchar(*p);
p=nome;
while(*p)
 putchar(*p++);
102
EX
EM
P
LO
#include <stdio.h>
#include <string.h>
main() {
char *p = "alo mundo";
int t;
printf(p);
printf("\n");
for (t=strlen(p)-1; t >-1; t--) 
 printf("%c", p[t]);
}
103
EX
EM
P
LO
#include <stdio.h>
#include <string.h>
void main(void) {
 int i;
 char *p1, c, s[80];
 p1=s;
 do {
 i = 0;
 while((c=getchar()) != '\n') {
 s[i]=c;
 i++;
 }
 s[i]='\0'; 
 while (*p1)
 printf(" %c", *p1++);
 printf("\n");
 } while (strcmp(s,"feito!"));
}
104
Matrizes de Ponteiros
— Como qualquer outro tipo básico, ponteiros podem ser organizados 
em matrizes:
int *listas[100];
— Para se atribuir o endereço de uma variável inteira, chamada var, ao 
terceiro elemento da matriz de ponteiros, deve-se escrever:
listas[2] = &var;
— Para encontrar o valor de var, escreve-se:
*listas[2];
105
Indireção Múl(pla
— Ocorre quando se tem um ponteiro que aponta para outro ponteiro 
que (finalmente) aponta para o valor.
— Indireção simples
— Indireção múltipla
ponteiro
endereçoendereço valorvalor
variável
endereçoendereço endereçoendereço valorvalor
ponteiro ponteiro variável
106
EX
EM
P
LO
#include <stdio.h>
void main(void)
{
 int x, *p, **q;
 x = 10;
 p = &x;
 q = &p;
 printf("%d", **q);
}
Diretrizes para Ponteiros
— Isolar ponteiros em rotinas especializadas
— Verificar ponteiros antes de usá-los
— Usar apontadores extras se contribuir para aumentar a legibilidade
— Simplificar expressões com apontadores
— Procurar formas seguras de controlar a alocação e a liberação de 
apontadores
— Documentar operações sobre apontadores
— Verificar, na liberação de listas, se a ordem de liberação dos 
apontadores é correta
108
EX
ER
C
ÍC
IO
S
1) Seja o seguinte trecho de programa:
int i=3,j=5;
int *p, *q;
p = &i;
q = &j;
Qual é o valor das seguintes expressões ?
a) p = &i b) *p - *q c) **&p d) 3* - *p/(*q)+7
2) Qual será a saída deste programa supondo que i ocupa o endereço 1000 
na memória?
main() {
int i=5, *p;
p = &i;
printf("%p %d %d %d %d \n", p, *p+2, **&p, 3**p, **&p+4);
}
109
EX
ER
C
ÍC
IO
S
3) Se i e j são variáveis inteiras e p e q ponteiros para int, quais das seguintes 
expressões de atribuição são ilegais?
a) p = &i; b) *q = &j; c) p = &*&i; d) i = (*&)j; e) i = *&j; f) i = *&*&j; 
g) q = *p; h) i = (*p)++ + *q
4) Qual é o resultado do seguinte programa?
#include <stdio.h>
 void main(){
 float vet[5] = {1.1,2.2,3.3,4.4,5.5};
 float *f;
 int i;
 f = vet;
 printf("contador/valor/valor/endereco/endereco");
 for(i = 0 ; i <= 4 ; i++){
 printf("\ni = %d",i);
 printf(" vet[%d] = %.1f",i, vet[i]);
 printf(" *(f + %d) = %.1f",i, *(f+i));
 printf(" &vet[%d] = %p",i, &vet[i]);
 printf(" (f + %d) = %p",i, f+i);
 }
 }
110
EX
ER
C
ÍC
IO
S
5) Quais serão as saídas do seguinte programa?
#include <stdio.h>
main () {
 int valor;
 int *p1;
 float temp;
 float *p2;
 char aux;
 char *nome = "Algoritmos";
 char *p3;
 int idade;
 int vetor[3];
 int *p4;
 int *p5;
 /* (a) */
 valor = 10;
 p1 = &valor;
 *p1 = 20;
 printf ("(a) %d \n", valor);
 /* (b) */
 temp = 26.5;
 p2 = &temp;
 *p2 = 29.0;
 printf ("(b) %.1f \n", temp);
 /* (c) */
 p3 = &nome[0];
 aux = *p3;
 printf ("(c) %c \n", aux);
 /* (d) */
 p3 = &nome[4];
 aux = *p3;
 printf ("(d) %c \n", aux);
 /* (e) */
 p3 = nome;
 printf ("(e) %c \n", *p3);
 /* (f) */
 p3 = p3 + 4;
 printf ("(f) %c \n", *p3);
 /* (g) */
 p3--;
 printf ("(g)%c \n", *p3);
 /* <h> */
 vetor[0] = 31;
 vetor[1] = 45;
 vetor[2] = 27;
 p4 = vetor; idade = *p4;
 printf ("(h) %d \n", idade);
 /* (i) */
 p5 = p4 + 1;
 idade = *p5;
 printf ("(i) %d \n", idade);
 /* (j) */
 p4 = p5 + 1;
 idade = *p4;
 printf ("(j) %d \n", idade);
 /* (l) */
 p4 = p4 - 2;
 idade = *p4;
 printf ("(l) %d \n", idade);
 /* (m) */
 p5 = &vetor[2] - 1;
 printf ("(m) %d \n", *p5);
 /* (n) */
 p5++;
 printf ("(n) %d \n", *p5);
}
111
EX
ER
C
ÍC
IO
S
6) Assumindo que pulo[] é um vetor do tipo int, quais das seguintes 
expressões referenciam o valor do terceiro elemento da vetor?
a) *(pulo + 2) b) *(pulo + 4) c) pulo + 4 d) pulo + 2
7) Supor as declarações: int mat[4], *p, x; 
Quais expressões são válidas? Justifique:
a) p= mat + 1; b) p= mat++; c) p= ++mat; d) x=(*mat)++;
8) O que fazem os seguintes programas?
#include <stdio.h>
void main(){
 int vet[] = {4,9,13};
 int i;
 for(i=0;i<3;i++){
printf("%d ",*(vet+i));
 }
}
#include <stdio.h>
void main(){
 int vet[] = {4,9,13};
 int i;
 for(i=0;i<3;i++){
 printf("%p ",vet+i);
 }
}
112
EX
ER
C
ÍC
IO
S
9) O que fazem os seguintes programas quando executados?
#include <stdio.h>
void main() {
 int vet[] = {4,9,12};
 int i,*ptr;
 ptr = vet;
 for(i = 0 ; i < 3 ; i++) {
 printf("%d ",*ptr++);
 }
}
#include <stdio.h>
void main(){
 int vet[] = {4,9,12};
 int i,*ptr;
 ptr = vet;
 for(i = 0 ; i < 3 ; i++) {
 printf("%d ",(*ptr)++);
 }
}
113
EX
ER
C
ÍC
IO
S
10) Seja vet um vetor de 4 elementos: TIPO vet[4]. Supor que depois da 
declaração, vet esteja armazenado no endereço de memória 1000 (ou seja, 
o endereço de vet[0]). Supor também que na máquina usada uma variável 
do tipo char ocupa 1 byte, do tipo int ocupa 4 bytes, do tipo float ocupa 4 
bytes e do tipo double ocupa 8 bytes.
Qual o valor de vet+1, vet+2 e vet+3 se:
a) vet for declarado como char?
b) vet for declarado como int?
c) vet for declarado como float?
d) vet for declarado como double?
114
FUNÇÕES
115
Conceitos
— Funções são os blocos de construção de C e o local onde toda a atividade do programa 
ocorre. Qualquer programa C possui ao menos uma função (main).
— Forma Geral:
tipo nome_da_função(lista de parâmetros) {
 corpo da função
}
tipo especifica o tipo de valor que o comando return da função devolve, podendo ser qualquer tipo 
válido. Se nenhum tipo é especificado, o compilador assume que a função devolve um resultado 
inteiro.
lista de parâmetros é uma lista de nomes de variáveis separados por vírgulas e seus tipos 
associados que recebem os valores dos argumentos quando a função é chamada. Uma função pode 
não ter parâmetros, neste caso a lista de parâmetros é vazia. Ainda assim os parêntesis são 
necessários.
116
Regras de Escopo
— As regras de escopo de uma linguagem são as regras que determinam se uma porção de 
código conhece ou tem acesso a outra porção de código ou dados.
— Em C, cada função é um bloco discreto de código. 
— Um código de uma função é privativo àquela função e não pode ser acessado por nenhum 
comando em outra função, exceto por meio de uma chamada à função
— O código que constitui o corpo de uma função é escondido do resto do programa e, a 
menos que use variáveis ou dados globais, não pode afetar ou ser afetado por outras 
partes do programa
— O código e os dados que são definidos internamente a uma função não podem interagir 
com o código ou dados definidos em outra função porque as duas funções têm escopos 
diferentes.
117
Regras de Escopo (cont)
— Variáveis locais:
— São as variáveis definidas internamente a uma função
— Existem somente durante a execução da função que as definiu
— Não podem manter seus dados entre chamadas da função, exceto 
se se usa o especificador de tipo de armazenamento static
— Em C, todas as funções estão no mesmo nível de escopo
— Por este motivo, C não é considerada uma linguagem estruturada 
em blocos
118
EX
EM
P
LO
#include <stdio.h>
int substring(char *string1, char *string2);
void main(void) {
 if(substring("C eh legal", "eh"))
 printf("É substring!\n");
 else
 printf("Não é substring!\n");
}
int substring(char *string1, char *string2) {
 int i;
 char *p1, *p2;
 
 for(i=0; string1[i]; i++) {
 p1=&string1[i];
 p2=string2;
 while(*p2 && *p2==*p1) {
 p1++;
 p2++;
 }
 if(!*p2)
 return 1;
 }
 return 0;
}
119
Argumentos
— Se uma função usa argumentos, então ela deve declarar variáveis 
que aceitem os valores dos argumentos.
— Essas variáveis são chamadas parâmetros formais da função.
— Parâmetros formais comportam-se como variáveis locais dentro da 
função: são criadas na entrada e destruídas na saída.
— A declaração ocorre após o nome da função (e segundo o padrão 
ANSI, entre os parêntesis)
120
Comando return
— Possui dois usos:
— Invoca uma saída imediata da função que o contém (faz com que a 
execução do programa retorne ao código chamador)
— É usado para devolver um valor
— Há duas maneiras pelas quais uma função termina sua execução (e retorna 
ao código qua a chamou):
— Ao executar o último comando da função (e o } )
— Quando o comando return é encontrado
— Forma Geral:
return expressao;
121
EX
EM
P
LO
#include <stdio.h>
int is_in(char *s, char c);
main() {
char *palavra = "alo mundo";
char o = 'o';
if (is_in(palavra, o))
printf("A palavra contém o caractere.");
else
printf("A palavra não contém o caractere.");
}
int is_in(char *s, char c) {
while (*s)
if (*s == c)
return 1;
else
s++;
return 0;
}
122
EX
EM
P
LO
#include <stdio.h>
int soma_um(void);
main()
{
int i;
for (i = 0; i < 10; i++)
printf("%d ", soma_um());
}
int soma_um(void)
{
static int num = 0;
return ++num;
}
123
EX
EM
P
LO
#include <stdio.h>
int pot(int n, int e);
int total=0;
void main(void) {
 int t=10;
 printf("%d %d %d", t, total, pot(t,2));
}
int pot(int n, int e) {
 total=n;
 
 for(; e>1; e--)
 total = total*n;
 return(total);
}
124
Argumentos
— Os argumentos usados para chamar a função devem ser compatíveis 
com os tipos de seus parâmetros.
— C é robusta: se os tipos forem incompatíveis, o compilador não gera 
uma mensagem de erro, mas ocorrem resultados inesperados.
— O uso de protótipos de funções pode ajudar a achar esses tipos de 
erros.
— Tal como as variáveis locais da função, os parâmetros formais 
podem ser usados em qualquer expressão permitida em C
125
Argumentos (cont)
Em C, podem ser passados argumentos
para subrotinas de duas maneiras:
Passagem por valor
Passagem por referência
126
Passagem por valor
— Parâmetro formal da função recebe uma cópia do valor do 
argumento.
— Consequência:
— As alterações feitas nos parâmetros formais da função não têm 
nenhum efeito nas variáveis usadas para chamá-la.
127
Passagem por referência
— O parâmetro formal da função recebe uma cópia do endereço do 
argumento (ponteiro).
— Consequências:
— Dentro da função, o endereço é usado para acessar o argumento 
real usado na chamada.
— Alterações feitas no parâmetro afetam a variáveis usada para 
chamar a função.
128
EX
EM
P
LO
#include <stdio.h>
int pot(int n, int e);
void main(void) {
 int t=10;
 printf("%d %d", t, pot(t,2));
}
int pot(int n, int e) {
 int total=n;
 for(e; e>1; e--)
 total = total*n;
 return(total);
}
Note que o valor da
variável t, usada como
argumento na
chamada de pot,
permanece inalterado,
de modo que a saída
deste programa será''10 100''.
129
EX
EM
P
LO
#include <stdio.h>
void troca(int *x, int *y);
void main( void ) {
 int a, b;
 scanf("%d %d", &a, &b);
 printf("a=%d b=%d\n", a, b);
 
 troca(&a, &b); 
 printf("a=%d b=%d\n", a, b);
}
void troca(int *x, int *y) {
 int temp;
 temp = *x;
 *x = *y;
 *y = temp;
}
Para a chamada por
referência, deve-se
passar para a função
um ponteiro para
cada argumento
que se deseja modificar
130
Funções e Matrizes
— Em C, um nome de matriz sem qualquer índice é um ponteiro para o 
primeiro elemento da matriz.
— Há 3 maneiras de se declarar um parâmetro que irá receber um 
ponteiro para matriz.
131
EX
EM
P
LO
#include <stdio.h>
void imprime(int num[10]);
void main(void) {
 int t[10], i;
 for(i=0; i<10; i++)
 t[i]=i;
 imprime(t);
}
void imprime(int num[10]) {
 int i;
 for(i=0; i<10; i++)
 printf("%d ", num[i]);
}
Caso 1) Declarando como uma 
matriz
● apesar de num ter sido 
declarado como uma matriz, o 
compilador C o converte 
automaticamente para um 
ponteiro de inteiros.
● isto ocorre porque nenhum 
parâmetro pode realmente 
receber uma matriz completa.
132
EX
EM
P
LO
#include <stdio.h>
void imprime(int num[]);
void main(void) {
 int t[10], i;
 for(i=0; i<10; i++)
 t[i]=i;
 imprime(t);
}
void imprime(int num[]) {
 int i;
 for(i=0; i<10; i++)
 printf("%d ", num[i]);
}
Caso 2) Especificando uma 
matriz sem dimensão
● Neste caso, num é declarado 
como uma matriz de inteiros de 
tamanho desconhecido.
● Os limites da matriz precisam ser 
respeitados, o que fica por conta 
do programador, pois C não testa 
tais limites. (Este método 
realmente define num como um 
ponteiro para inteiros).
133
EX
EM
P
LO
#include <stdio.h>
void imprime(int *num);
void main(void) {
 int t[10], i;
 for(i=0; i<10; i++)
 t[i]=i;
 imprime(t);
}
void imprime(int *num) {
 int i;
 for(i=0; i<10; i++)
 printf("%d ", num[i]);
}
Caso 3) Usando Ponteiros
● Isto é permitido porque qualquer 
ponteiro pode ser indexado 
usando [], como se fosse uma 
matriz.
● Esta é a forma mais comum em 
programas profissionais.
134
EX
EM
P
LO
#include <stdio.h>
#include <string.h>
void inverte(char *s);
void main(void) {
 char *msg="Eu gosto de C";
 inverte(msg);
}
void inverte(char *s) {
 int i;
 for(i=strlen(s)-1; i>=0; i--)
 putchar(s[i]);
}
135
EX
EM
P
LO
#include <stdio.h>
int substring(char *string1, char *string2);
void main(void) {
 if(substring("C eh legal", "eh"))
 printf("É substring!\n");
 else
 printf("Não é substring!\n");
}
int substring(char *string1, char *string2) {
 int i;
 char *p1, *p2;
 
 for(i=0; string1[i]; i++) {
 p1=&string1[i];
 p2=string2;
 while(*p2 && *p2==*p1) {
 p1++;
 p2++;
 }
 if(!*p2)
 return 1;
 }
 return 0;
}
136
Recursão
— Muitos problemas têm a seguinte propriedade: 
— cada instância do problema contém uma instância menor do mesmo 
problema. Dizemos que esses problemas têm estrutura recursiva. 
— Para resolver um tal problema podemos aplicar o seguinte método:
— se a instância em questão é pequena,
 resolva-a diretamente (use força bruta se necessário);
— senão,
 reduza-a a uma instância menor do mesmo problema,
 aplique o método à instância menor e
 volte à instância original. 
— A aplicação desse método produz um algoritmo recursivo.
137
EX
EM
P
LO
#include <stdio.h>
int fatorial (int n);
int main()
{
printf("%d", fatorial(5));
return 0;
}
int fatorial(int n)
{
if ((n == 1) || (n == 0))
return 1;
else
return n * fatorial(n - 1);
}
138
EX
EM
P
LO
#include <stdio.h>
int fibonacci (int n);
int main()
{
printf("%d", fibonacci(10));
return 0;
}
int fibonacci(int n)
{
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
139
EX
EM
P
LO
#include <stdio.h>
int maximo (int n, int v[]);
int main()
{
int x[5] = {4, 3, 5, 7, 6};
printf("%d", maximo(5, x));
return 0;
}
int maximo(int n, int v[])
{
if (n == 1)
 return v[0];
else {
 int x;
 x = maximo(n - 1, v);
 if (x > v[n - 1])
 return x;
 else
 return v[n - 1];
}
}
Considerações sobre a Recursão
— Só usar recursão quando puder provar que ela tem limite
— Usar contadores de segurança para evitar a recursão infinita 
— Controlar tamanho da pilha
— Não usar a recursão para cálculos simples (como fatoriais)
Diretrizes para funções: Nomes signi$ca(vos
— Identificadores de módulos, subprogramas, funções, tipos, variáveis 
devem ser bem escolhidos para aumentar legibilidade
— Usar substantivos para nomear objetos, variáveis, constantes e tipos
Salario (melhor que Apagar ou Pagar)
— Utilizar verbos para nomear funções
LerCaracteres, LerSegCar, CalcularSegMov
— Utilizar formas do verbo “ser” e “estar” para funções lógicas. 
SãoIguais, ÉZero, EstáPronto
if SãoIguais (A , B)
142
Argumentos da função main
— Frequentemente, é necessário passar informações para um 
programa antes que ele inicie a executar
— Isto é feito mediante os argumentos da linha de comando. Exemplo:
marilton@redbull:~$ ./prog -p arq.txt
— Neste exemplo, prog poderia ser o programa, -p poderia ser uma 
opção para imprimir os dados do arquivo arq.txt
— Todo programa C executa a partir da função main
— Existem 2 argumentos internos especiais que são usados para 
receber os argumentos da linha de comando: argc e argv
143
Argumentos da função main (cont)
— argc
— Contém o número de argumentos de linha de comando digitados pelo usuário
— Obviamente, é um inteiro
— Vale ao menos 1 porque o próprio nome do programa é considerado como primeiro argumento.
— argv
— É um ponteiro para uma matriz de ponteiros para caractere (char *argv[]);
— Cada elemento nessa matriz aponta para um argumento da linha de comando
— Todos os argumentos da linha de comando são strings (quaisquer números terão que ser 
convertidos pelo programa para o formato adequado)
144
EX
EM
P
LO
#include <stdio.h>
#include <stdlib.h> //por causa de exit()
void main(int argc, char *argv[]) {
 if(argc!=2) {
 printf("Erro: Informe seu nome como parâmetro!\n");
 exit(1);
 }
 printf("Olá, %s!\n", argv[1]);
}
145
EX
EM
P
LO
bib.h
int fatorial (int n);
bib.c
#include "bib.h"
int fatorial (int n) {
 
 if ((n==1)||(n==0)) return 1;
 else return n*fatorial(n-1);
 
}
principal.c
#include <stdio.h>
#include "bib.h"
main() {
 int n;
 
 printf("Informe n para o fatorial: ");
 scanf("%d", &n);
 
 printf("fat(%d) = %d", n, fatorial(n));
}
 gcc principal.c bib.c -o teste
146
EX
ER
C
ÍC
IO
S
1) Modifique o programa do exercício 2 do slide 51, de modo a fazer o 
cálculo da média das notas utilizando uma função, que recebe como 
parâmetros as notas N1, N2 e MT, e devolve a média M. O programa 
verifica se o aluno atingiu a média 7 e em caso positivo, o programa 
imprime a mensagem ''aprovado por média''. Caso contrário, o programa 
chama uma outra função que calcula e retorna o valor necessário na 
optativa, que será impresso no programa principal. 
2) Faça um programa que calcule e imprima o fatorial de um número N. 
Este programa deve usar uma função, a qual calcula o fatorial do número 
lido. Não esqueça de testar as restrições cabíveis a N.
147
EX
ER
C
ÍC
IO
S
3) Faça um programa utilizando uma função que lê um número inteiro e verifica 
se este número é primo ou não, imprimindo uma mensagem condizente. 
4) Faça um programa que lê dois númerosinteiros, A e B, e, com uma função, 
testa se estes números são amigos. Dizemos que dois números são amigos se cada 
um deles é igual a soma dos divisores próprios do outro. Os divisores próprios de 
um número positivo N são todos os divisores inteiros positivos de N exceto o 
próprio N. 
5) Modifique o programa do exercício 2, de modo que o número N seja passado 
como parâmetro na linha de comando.
6) Modifique o programa do exercício anterior, transformando a função "fatorial" 
em uma função recursiva.
148
EX
ER
C
ÍC
IO
S
7) Faça um programa que lê n números decimais (n fornecido pelo 
usuário), armazenando-os em um vetor. Logo após, uma função deve 
retirar os números duplicados que eventualmente possam existir neste 
vetor, deixando apenas uma ocorrência de cada número. Ao final, o vetor 
resultante deve ser impresso na tela.
8) Faça um programa que leia uma string (de 80 caracteres) chamada 
linha e, com uma função, identifique cada palavra (substring) desta linha 
copiando-a para um novo vetor. Ao final, o programa deve imprimir as 
palavras separadas, uma palavra por linha. Dicas: i) faça uma função para 
identificar o fim e/ou o início de cada substring em linha; e, ii) utilize o 
modo de leitura apresentado no slide 83.
149
ESTRUTURAS
150
Estruturas
— A linguagem C permite ao usuário criar tipos de dados de 5 formas 
diferentes:
— Estrutura (chamado tipo de dado agregado)
— Campo de Bit
— União
— Enumeração
— Usando typedef
151
Estruturas (cont)
— Uma estrutura é uma coleção de variáveis referenciadas por um 
nome
— Útil quando se deseja agrupar informações ("registros")
— Uma definição de estrutura forma um modelo que pode ser usado 
para criar variáveis de estrutura
— As variáveis que formam a estrutura são chamados membros (ou 
campos ou elementos ou registros).
— Geralmente, todos os membros de uma estrutura são relacionados
152
Criando uma estrutura
struct end {
 char nome[30];
 char rua[40];
 char cidade[20];
 char estado[3];
 unsigned long int cep;
};
No trecho acima, nenhuma variável foi de fato declarada. Apenas a forma 
dos dados foi definida. Para declarar uma variável do tipo end deve-se 
escrever:
struct end info;
153
Criando uma estrutura (cont)
— Quando uma variável de estrutura (como end) é declarada, o 
compilador C aloca automaticamente memória suficiente para 
acomodar todos os seus membros.
— Exemplo (assumindo caracteres com 1 byte e inteiros longos com 4 
bytes):
— nome (30 bytes)
— rua (40 bytes)
— cidade (20 bytes)
— estado (3 bytes)
— cep (4 bytes)
154
Declarando Variáveis
struct {
 char nome[30];
 char rua[40];
 char cidade[20];
 char estado[3];
 unsigned long int cep;
} info;
struct end {
 char nome[30];
 char rua[40];
 char cidade[20];
 char estado[3];
 unsigned long int cep;
} info, info2, info3;
155
Forma Geral
struct identificador
{
 tipo variável-registro;
 tipo variável-registro;
 tipo variável-registro;
 ...
} variáveis-estutura;
156
Referenciando Elementos
— A forma geral para se acessar um elemento de estrutura é:
nome_da_estrutura.nome_do_elemento
— Elementos individuais de estruturas são referenciados por meio do 
operador ponto.
info.cep = 96010;
— Atribui o valor 96010 ao campo cep da variável estrutura info.
— Exemplos:
printf("%d", info.cep);
scanf("%d", &info.cep);
157
Referenciando Elementos (cont)
int i; char c;
while((c=getchar()) != '\n') 
{
 info.nome[i]=c;
 i++;
}
info.nome[i]='\0';
Ou
gets(info.nome)
int i;
while((info.nome[i] != '\0') 
{
 putchar(info.nome[i]);
 i++;
}
Ou
printf("%s",info.nome)
158
EX
EM
P
LO
#include <stdio.h>
void main(void) {
 struct {
 int a;
 int b;
 } x,y;
 x.a = 10;
 y=x;
 printf("%d", y.a);
}
Atribuição de Estruturas
159
Matrizes de Estruturas
— É o uso mais comum para estruturas...
— Primeiro definir uma estrutura
— Depois, declarar uma variável matriz desse tipo
struct end info[100];
— Cria 100 conjuntos de variáveis, onde cada variável está organizada 
conforme definido na estrutura end.
160
EX
EM
P
LO
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct end {
 char nome[31];
 char rua[41];
 char cidade[21];
 char estado[3];
 unsigned long int cep;
} info[MAX];
void cria_lista(void);
void insere(void);
void apaga(void);
void imprime(void);
int menu(void);
int livre(void);
void ler_string(char palavra[100], int tamanho);
161
EX
EM
P
LO
int main(void) {
 int escolha;
 cria_lista();
 for( ; ; ) {
 escolha = menu();
 switch(escolha) {
 case 1: insere();
 break;
 case 2: apaga();
 break;
 case 3: imprime();
 break;
 case 4: exit(0);
 break;
 }
 }
}
162
EX
EM
P
LO
void cria_lista(void) {
 int i;
 for( i=0; i<MAX; i++)
 info[i].nome[0]='\0';
}
int menu(void) {
 int c=0;
 do {
 printf("-- MENU:\n");
 printf("\t 1. Inserir um nome\n");
 printf("\t 2. Excluir um nome\n");
 printf("\t 3. Listar o arquivo\n");
 printf("\t 4. Sair\n");
 printf("-- Digite sua escolha: ");
 scanf("%d", &c);
 } while(c<=0 || c>4);
 getchar();
 return c;
}
163
EX
EM
P
LO
void ler_string(char palavra[100], int tamanho) {
 int i = 0;
 char c;
 c = getchar();
 while ((c != '\n') && (i < tamanho)) {
 palavra[i++] = c;
 c = getchar();
 }
 palavra[i] = '\0';
 if (c != '\n') {
 c = getchar();
 while((c != '\n') && (c != EOF)) {
 c = getchar();
 }
 }
}
164
EX
EM
P
LO
void insere(void) {
 int posicao;
 posicao=livre();
 if(posicao == -1) {
 printf("\nEstrutura Cheia!!");
 return;
 }
 printf("-- Registro %d:\n", posicao);
 printf("\t Nome: ");
 ler_string(info[posicao].nome, 30);
 printf("\t Rua: ");
 ler_string(info[posicao].rua, 40);
 printf("\t Cidade: ");
 ler_string(info[posicao].cidade, 20);
 printf("\t Estado: ");
 ler_string(info[posicao].estado, 2);
 printf("\t CEP: ");
 scanf("%d", &info[posicao].cep); 
}
165
EX
EM
P
LO
int livre(void) {
 int i;
 for( i=0; info[i].nome[0] && i< MAX; i++);
 if( i == MAX ) return -1; 
 return i;
}
void apaga(void) {
 int posicao;
 
 printf("Número do Registro: ");
 scanf("%d",&posicao);
 
 if(posicao >=0 && posicao < MAX)
 info[posicao].nome[0]='\0';
}
166
EX
EM
P
LO
void imprime(void)
{
 int i;
 for( i=0; i < MAX; i++)
 if(info[i].nome[0] != '\0')
 {
 printf("-- Registro %d:\n", i);
 printf("\t Nome: %s", info[i].nome);
 printf("\t Rua: %s", info[i].rua);
 printf("\t Cidade: %s", info[i].cidade);
 printf("\t Estado: %s\n", info[i].estado);
 printf("\t CEP: %lu\n", info[i].cep);
 }
}
167
Typedef
— C permite que sejam definidos explicitamente novos nomes aos 
tipos de dados utilizando a palavra-chave typedef 
— Não se está criando uma nova classe de dados, mas apenas 
definindo um novo nome para tipos já existentes.
— Exemplo:
typedef float nota;
nota prova01;
168
EX
EM
P
LO
#include <stdio.h>
typedef struct {
 int dia;
 int mes;
 int ano; 
} data;
void main(void) {
 data aniversario;
 
 aniversario.dia = 14;
 aniversario.mes = 1;
 aniversario.ano = 1975;
 
 printf("%d / %d / %d.", aniversario.dia, aniversario.mes, aniversario.ano);
}
169
EX
EM
P
LO
#include <stdio.h>
#include <math.h>
typedef struct {
int x;
int y;
} ponto;
typedef struct {
ponto cie; //canto inferior esquerdo
ponto csd; //canto superior direito
} retangulo;
typedefstruct {
ponto centro;
float raio;
} circulo;
float distancia(int x1, int y1, int x2, int y2)
{
return sqrt(pow(fabs(x2 - x1), 2) + pow(fabs(y2 - y1), 2));
}
170
EX
EM
P
LO
int main(void) {
ponto A;
ponto B;
circulo C;
retangulo R;
float dist;
printf("Informe as coordenadas do ponto A: ");
scanf("%d %d", &A.x, &A.y);
printf("Informe as coordenadas do ponto B: ");
scanf("%d %d", &B.x, &B.y);
R.cie = A;
R.csd = B;
printf("Coordenada do CIE de R: (%d,%d)\n", R.cie.x, R.cie.y);
printf("Coordenada do CSD de R: (%d,%d)\n\n", R.csd.x, R.csd.y);
C.centro = B;
C.raio = 10.0;
printf("Coordenada do centro de C: (%d,%d)\n", C.centro.x, C.centro.y);
printf("Raio de C: %f\n", C.raio);
dist = distancia(C.centro.x, C.centro.y, A.x, A.y);
if (dist <= C.raio)
printf("O ponto A está DENTRO do círculo C.\n");
else
printf("O ponto A está FORA do círculo C.\n");
printf("Distância do ponto A ao centro de C: %f", dist);
return 0;
}
Considerações sobre o typedef
— Nunca redefinir um tipo predefinido do ambiente
— Isso vale para tipos predefinidos da linguagem, em bibliotecas e 
em plataformas de desenvolvimento
— Denominação de tipos
— Usar nomes de tipos funcionalmente orientados
— Usar nomes e tipos orientados para as espécies de dados que 
representam (coordenadas, moedas, idades, etc)
172
Uniões
— Uma união é um tipo de dado que pode ser usado de muitas maneiras diferentes.
— Por exemplo, uma união pode ser interpretada como sendo inteiro em uma operação e um 
float ou double em outra.
— Embora as uniões possam tomar a aparência de uma estrutura, elas são muito diferentes. 
— Uma união pode conter um grupo de muitos tipos de dados, todos eles compartilhando a 
mesma localização na memória.
— No entanto, uma união só pode conter informações de um tipo de dados de cada vez.
— Sintaxe:
union nome_tipo {
 tipo var1;
 tipo var2;
 tipo var3;
};
173
Uniões (cont)
union varios_tipos {
 char c;
 int i;
 float f;
 double d;
} tdata;
— Faz-se referência aos membros da união usando o operador ponto:
tdata.d = 1.3;
174
EX
EM
P
LO
#include <stdio.h>
union varios_tipos {
 char c;
 int i;
 float f;
 double d;
} tdata;
void main(void) {
 tdata.c='b';
 printf("%c\n", tdata.c);
 tdata.i=1234;
 printf("%d\n", tdata.i);
 tdata.f=12.34;
 printf("%f\n", tdata.f);
 tdata.d=123456.78E+12;
 printf("%lf\n", tdata.d);
 printf("\n%c\n", tdata.c);
 printf("%d\n", tdata.i);
 printf("%f\n", tdata.f);
 printf("%lf\n", tdata.d);
 printf("\nO tamanho desta união é: %d bytes.", sizeof(union varios_tipos)); 
}
175
Enumerações
— Um tipo de dado enum permite criar um tipo de dado de sua escolha 
em itens.
— enum é útil quando a informação pode ser mais bem representada 
por uma lista, como por exemplo, de valores inteiros indicando o 
número de meses do ano ou o número de dias da semana.
Diretrizes para Enumeração
— Usar enumerações para facilitar a leitura
— Usar enumerações para aumentar a confiabilidade, promovendo 
checagem em tempo de compilação
— Usar enumerações para facilitar modificações
— Testar valores inválidos e reservar a entrada para representar 
valores válidos
177
EX
EM
P
LO
#include <stdio.h>
enum meses {
 janeiro = 1, fevereiro, marco, abril, maio, junho, julho, agosto, setembro,
 outubro, novembro, dezembro
};
void main (void) {
 int mes_corrente;
 int soma, dif;
 enum meses fim;
 printf ("Digite o mês corrente (1 a 12): ");
 scanf ("%d", &mes_corrente);
 fim = dezembro;
 soma = (int) mes_corrente;
 dif = (int) fim - (int) mes_corrente;
 printf ("\n%d meses a menos, pois faltam %d para acabar este ano.\n", soma, dif);
}
178
EX
ER
C
ÍC
IO
S
1) Compile o programa do slide 160. Teste-o.
2) Modifique o programa do slide 160, de modo que ele permita apagar somente 
os dados de uma pessoa com Nome e Sobrenome fornecidos pelo usuário do 
programa. Porém, antes de apagar os dados, o programa deve perguntar se o 
usuário deseja mesmo apagar... Sugestão: fazer uma função que busca na lista a 
posição (índice) onde se encontram armazenados os dados de uma pessoa de 
Nome e Sobrenome (ex: Joao Silva).
3) Modifique o programa do slide 160, de modo que ele permita também a 
impressão de todos os dados de uma pessoa com Nome e Sobrenome. Sugestão: 
usar a função de busca feita na questão 2.
4) Modifique o programa do slide 160, de modo que antes de inserir um novo 
nome, ele teste se o referido nome já está presente na lista (testar ambos Nome e 
Sobrenome). Sugestão: usar a função de busca feita na questão 2.
179
ARQUIVOS
180
Streams vs. Arquivos
— O sistema de E/S da linguagem C fornece uma interface consistente 
ao programador, independentemente do dispositivo real que é 
acessado.
— Este sistema (que é uma abstração) é chamado de stream e o 
dispositivo real é chamado de arquivo.
— Daí decorre que, em C, todos os dispositivos são encarados como 
arquivos
181
Streams
— O sistema de arquivos de C é projetado para trabalhar com uma 
ampla variedade de dispositivos, incluindo:
— terminais,
— acionadores de disco, e
— acionadores de fita.
— Embora cada um dos dispositivos seja muito diferente, o sistema de 
arquivo com buffer transforma-os em um dispositivo lógico 
chamado de stream.
182
Streams (cont)
— Todas as streams comportam-se de forma semelhante.
— Pelo fato de as streams serem totalmente independentes do 
dispositivo, a mesma função pode escrever em um arquivo em disco 
ou em algum outro dispositivo, como o console.
— Existem dois tipos de streams: texto e binária.
183
Streams de Texto
— Um stream de texto é uma sequência de caracteres.
— O padrão C ANSI permite (mas não exige) que uma stream de texto 
seja organizada em linhas terminadas por um caractere de nova 
linha.
— Porém, o caractere de nova linha é opcional na última linha e é 
determinado pela implementação.
184
Streams Binárias
— Uma stream binária é uma sequência de bytes com uma 
correspondência de um para um com aqueles encontrados no 
dispositivo externo.
— O número de bytes escritos (ou lidos) é o mesmo que o encontrado 
no dispositivo externo.
— Porém, um número definido pela implementação de bytes nulos 
pode ser acrescentado a um stream binário.
— Esse bytes nulos poderiam ser usados para aumentar a informação 
para que ela preenchesse um setor de um disco, por exemplo.
185
Arquivos
— Em C, um arquivo pode ser qualquer coisa, desde um arquivo em disco até um 
terminal ou uma impressora.
— Associa-se um stream com um arquivo específico realizando uma operação de 
abertura.
— Uma vez o arquivo aberto, informações podem ser trocadas entre ele e o seu 
programa.
— Nem todos os arquivos apresentam os mesmos recursos.
— Por exemplo, um arquivo em disco pode suportar acesso aleatório 
(sequencial), enquanto um teclado não pode.
— Isso releva um ponto importante sobre o sistema de E/S de C: todas as streams 
são iguais, mas não todos os arquivos.
186
Arquivos (cont)
— Se o arquivo pode suportar acesso aleatório
— Abrir este arquivo inicializa o indicador de posição no arquivo para o 
começo do arquivo
— Quando cada caractere é lido ou escrito no arquivo, o indicador de 
posição é incrementado, garantindo progressão através do arquivo.
— Um arquivo é desassociado de uma stream específica por meio de uma 
operação de fechamento.
— Se um arquivo aberto para saída for fechado, o conteúdo, da sua stream 
associada será escrito no dispositivo externo. Este processo é geralmente 
referido como descarga (flushing) da stream e garante que nenhuma 
informação seja acidentalmente deixada no buffer do disco.
187
Arquivos (cont)
— Todos os arquivossão fechados automaticamente quando o 
programa termina normalmente, com
— main() retornando ao sistema operacional ou
— uma chamada a exit()
— Os arquivos não são fechados quando um programa quebra (crash) 
ou quando ele chama abort().
188
Fundamentos
— Cada stream associada a um arquivo tem uma estrutura de controle 
de arquivo do tipo FILE. Esta estrutura é definida no cabeçalho 
stdio.h.
— O sistema de arquivos C ANSI é composto de diversas funções 
interrelacionadas.
— Estas funções exigem o cabeçalho stdio.h e a maioria começa com a 
letra "f".
189
Nome Função
fopen() abre um arquivo
fclose() fecha um arquivo
puts() escreve um caractere
fputs() escreve um caractere em um stream
gets() lê um caractere
fgets() lê um caractere de um stream
fseek() posiciona um arquivo em um byte específico
fprintf() o mesmo que printf() para console
fscanf() o mesmo que scanf() para console
feof() devolve verdadeiro para fim de arquivo
ferror() devolve verdadeiro se ocorreu algum erro
rewind() recoloca o indicador de posição para o início do arquivo
remove() apaga um arquivo
fflush() descarrega um arquivo
190
— arquivo de cabeçalho stdio.h fornece os protótipos para as funções de E/S e define estes três 
tipos: size_t, fpos_t e FILE
— Os tipos size_t e fpos_t são essencialmente o mesmo que um unsigned.
— O tipo FILE será discutido logo adiante
— stdio.h também define várias macros. As mais relevantes são: NULL, EOF, FOPEN_MAX, 
SEEK_SET, SEEK_CUR e SEEK_END.
— A macro NULL define um ponteiro nulo
— A macro EOF é geralmente definida como –1 e é o valor devolvido quando uma função de 
entrada tenta ler além do final do arquivo
— FOPEN_MAX, define um valor inteiro que determina o número de arquivos que podem estar 
abertos ao mesmo tempo
— As outras macros são usadas com fseek(), que é uma função que executa acesso aleatório 
em um arquivo.
191
Ponteiro de Arquivo
— Um ponteiro de arquivo é um ponteiro para informações que 
definem várias coisas sobre o arquivo:
— nome, status e a posição atual do arquivo
— Um ponteiro de arquivo é uma variável ponteiro do tipo FILE.
— Para ler ou escrever arquivos, seu programa precisa usar ponteiros 
de arquivo. Para obter uma variável ponteiro de arquivo, use o 
comando:
FILE *fp;
192
Abrindo um Arquivo
— A função fopen() abre uma stream para uso e associa um arquivo a 
ela
— Ela retorna o ponteiro de arquivo associado a este arquivo
FILE fopen(const char* nomearq, const char* modo*);
onde nomearq é um ponteiro para uma cadeia de caracteres que forma 
um nome válido de arquivo e pode incluir uma especificação de 
caminho de pesquisa (path).
193
Modo Significado
r abre arquivo texto para leitura
w cria arquivo texto para escrita
a anexa ao arquivo texto
rb abre arquivo binário para leitura
wb cria arquivo binário para escrita
ab anexa ao arquivo binário
r+ abre arquivo texto para leitura/escrita
w+ cria arquivo texto para leitura/escrita
a+ anexa ao arquivo texto para leitura/escrita
r+b abre arquivo binário para leitura/escrita
w+b cria arquivo binário para leitura/escrita
a+b anexa ao arquivo binário para leitura/escrita
194
Para abrir um arquivo
FILE *fp;
if((fp = fopen( "arquivo.txt", "w")) == NULL ) {
 printf("nao foi possivel criar o arquivo\n");
 exit(1);
}
— Neste caso, qualquer erro na abertura do arquivo será detectado 
(e.g., disco cheio ou protegido contra gravação). 
195
Algumas Considerações
— Confirmar o sucesso de fopen() antes de tentar qualquer outra operação sobre o arquivo!
— Se você usar fopen() para abrir um arquivo com permissão para escrita, qualquer arquivo já 
existente com esse nome será apagado e um novo arquivo será iniciado
— Se nenhum arquivo com este nome existe, então o arquivo será criado. 
— Se você deseja adicionar ao final do arquivo, deve usar o modo "a".
— Arquivos já existentes só podem ser abertos para operações de leitura.
— Se o arquivo não existe, um erro é devolvido.
— Se um arquivo é aberto para operações de leitura/escrita, ele não será apagado caso já exista e, 
senão existir, ele será criado.
196
Fechando um Arquivo
— A função fclose() fecha uma stream que foi aberta por meio de uma chamada a 
fopen()
— Ela escreve qualquer dado que ainda permanece no buffer de disco no arquivo e, 
então, fecha normalmente o arquivo em nível de sistema operacional
— Se um arquivo é aberto para operações de leitura/escrita, ele não será apagado 
caso já exista e, senão existir, ele será criado.
— Um fclose() também libera o bloco de controle de arquivo associado à stream, 
deixando-o disponível para reutilização.
— Em muitos casos, há um limite do sistema operacional para o número de arquivos 
abertos simultaneamente, assim, você deve fechar um arquivo antes de abrir 
outro.
197
Fechando um Arquivo (cont)
— A função fclose() tem o seguinte protótipo:
int fclose(FILE *fp);
onde fp é o ponteiro de arquivo devolvido pela chamada a fopen().
— Um valor de retorno zero significa uma operação de fechamento bem 
sucedida.
— Qualquer outro valor indica um erro.
— A função padrão ferror() pode ser utilizada para determinar e informar 
qualquer problema.
— Geralmente, fclose() falhará quando um disco tiver sido retirado 
prematuramente do acionador ou não houver mais espaço no disco.
198
EX
EM
P
LO
#include <stdio.h>
#define MAX 120
main() {
FILE *fp;
char nome_arq[50], linha[120];
printf("entre com o nome do arquivo\n");
scanf("%s",nome_arq);
if((fp = fopen( nome_arq, "r")) == NULL ) {
printf("Erro ao abrir o arquivo %s\n", nome_arq);
exit(1);
}
while ( fgets(linha,MAX,fp) != NULL ) {
printf("%s", linha );
}
}
199
EX
EM
P
LO
#include <stdio.h>
main () {
 FILE *fp;
 char nome_arquivo[32];
 double a;
 printf ("Informe o nome do arquivo: ");
 scanf ("%s", nome_arquivo);
 fp = fopen (nome_arquivo, "w");
 printf ("Informe um numero (-999 para sair): ");
 scanf ("%lf", &a);
 while (a != -999) {
 fprintf (fp, "%10.4lf", a);
 printf ("Informe um numero (-999 para sair): ");
 scanf ("%lf", &a);
 }
 fclose (fp);
 fp = fopen (nome_arquivo, "r");
 printf ("\n***** conteudo do arquivo criado ******\n");
 while (fscanf (fp, "%lf", &a) != EOF)
 printf ("\n\t %lf", a);
 fclose (fp);
}
200
EX
EM
P
LO
#include <stdio.h>
#include <stdlib.h>
int main (void ) {
 int inum=10;
 float fnum=2.5;
 double pi=3.141516;
 char c='Z';
 FILE *pa;
 char *nome = "texto.txt";
 if (( pa = fopen(nome, "w+b")) == NULL) {
 printf("\n\nNao foi possivel abrir o arquivo para escrita.\n");
 exit(1);
 }
 fwrite(&inum, sizeof(int), 1, pa);
 fwrite(&fnum, sizeof(float), 1, pa);
 fwrite(&pi, sizeof(double), 1, pa);
 fwrite(&c, sizeof(char), 1, pa);
 rewind(pa);
 fread(&inum, sizeof(int), 1, pa);
 fread(&fnum, sizeof(float), 1, pa);
 fread(&pi, sizeof(double), 1, pa);
 fread(&c, sizeof(char), 1, pa);
 printf("%d, %f, %lf, %c\n", inum, fnum, pi, c);
 fclose(pa);
 exit(0);
}
Arquivos Binários
201
EX
EM
P
LO
 #include <stdio.h>
 /* descrição de registro aleatório - pode ser qualquer uma */
 struct rec
 {
 int x,y,z;
 }; 
 /* grava e depois lê 10 registros arbitrários
 do arquivo "junk". */
 int main()
 {
 int i,j;
 FILE *f;
 struct rec r;
 /* cria o arquivo de 10 registros */
 f=fopen("junk","w");
 if (!f)
 return 1;
 for (i=1;i<=10; i++)
 {
 r.x=i;
 fwrite(&r,sizeof(struct rec),1,f);
 }
 fclose(f);
//segue no próximo slide
202
EX
EM
P
LO
 /* lê os 10 registros */
 f=fopen("junk","r");
 if (!f)

Continue navegando