Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

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)return 1;
 for (i=1;i<=10; i++)
 { 
 fread(&r,sizeof(struct rec),1,f); 
 printf("%d\n",r.x); 
 } 
 fclose(f);
 printf("\n"); 
 /* usa fseek para ler os 10 registros 
 em ordem inversa */
 f=fopen("junk","r");
 if (!f) 
 return 1;
 for (i=9; i>=0; i--)
 {
 fseek(f,sizeof(struct rec)*i,SEEK_SET);
 fread(&r,sizeof(struct rec),1,f); 
 printf("%d\n",r.x); 
 }
 fclose(f);
 printf("\n"); 
 
//segue no próximo slide
203
EX
EM
P
LO
 /* usa fseek para ler todo os outros registros */
 f=fopen("junk","r");
 if (!f)
 return 1;
 fseek(f,0,SEEK_SET);
 for (i=0;i<5; i++) 
 {
 fread(&r,sizeof(struct rec),1,f);
 printf("%d\n",r.x); 
 fseek(f,sizeof(struct rec),SEEK_CUR);
 }
 fclose(f);
 printf("\n"); 
 /* usa fseek para ler o 4º registro,
 altere-o e escreva-o de volta */
 f=fopen("junk","r+");
 if (!f)
 return 1;
 fseek(f,sizeof(struct rec)*3,SEEK_SET);
 fread(&r,sizeof(struct rec),1,f);
 r.x=100; 
 fseek(f,sizeof(struct rec)*3,SEEK_SET);
 fwrite(&r,sizeof(struct rec),1,f); 
 fclose(f); 
 printf("\n"); 
 
//segue no próximo slide
204
EX
EM
P
LO
 /* lê os 10 registros para garantir
 que o 4º arquivo foi alterado */
 f=fopen("junk","r");
 if (!f)
 return 1;
 for (i=1;i<=10; i++)
 {
 fread(&r,sizeof(struct rec),1,f); 
 printf("%d\n",r.x); 
 }
 fclose(f);
 return 0; 
 } 
//FIM
205
EX
ER
C
ÍC
IO
S
1) Modifique o programa do slide 160, de modo a incluir duas novas 
opções no menu principal. Gravar Lista de Endereços em Arquivo e 
Recuperar Lista de Endereços de Arquivo. Implemente estas novas 
rotinas, sempre solicitando ao usuário que informe o nome do 
arquivo para cada operação. Faça testes manipulando tanto com 
arquivos binários quanto com arquivos texto.
206
ALOCAÇÃO DINÂMICA
207
Alocação de Memória
— "Alocação de memória" diz respeito a como a memória (necessária 
para o armazenamento dos dados) é reservada em um programa
— Existem 2 formas de um programa em C alocar memória:
— Estática
— Dinâmica
208
Alocação Está(ca
— Ocorre na declaração de variáveis globais e variáveis locais;
— No caso de variáveis globais e variáveis locais estáticas, o 
armazenamento é fixo durante todo o tempo de execução do 
programa;
— Variáveis globais são alocadas em tempo de compilação;
— No caso de variáveis locais, o armazenamento dura o tempo de vida 
da variável.
209
Pilha
Programa
Variáveis
Globais
Memória
Livre
heap
Memória do Sistema
Variáveis
Locais
baixa
alta
Mapa da Memória
210
Alocação Dinâmica
— Para a alocação estática, é necessário que se saiba de antemão 
(antes do início do programa) a quantidade de memória que será 
necessária;
— Estimativas podem ser feitas, porém há o risco de sub ou 
superestimar;
— Assim, muitas vezes é necessário que um programa possa ir 
ajustando a memória a ser usada durante sua execução;
— "Ajustar" = alocar ou desalocar
211
Alocação Dinâmica (cont)
— Alocação dinâmica é o método pelo qual um programa ajusta 
dinamicamente a quantidade de memória a ser usada durante sua 
execução;
— Permite otimizar o uso da memória 
— É implementado mediante funções de alocação/liberação da 
memória, as quais o programador precisa usar de maneira coerente
212
Mapa da Memória
Pilha
Programa
Variáveis
Globais
Memória
Livre
heap
Memória do Sistema
Variáveis
Locais
baixa
alta
Variáveis 
Alocadas
Dinamicamente
213
Alocação Dinâmica
— Principais funções C para alocação dinâmica de memória:
— malloc e free;
— Implementadas na biblioteca stdlib.h
— Há diversas outras funções mais específicas, as quais normalmente 
estão implementadas em stdlib.h
214
Malloc
— Serve para alocar memória;
— Devolve um ponteiro para o início da quantidade de memória 
alocada;
— Exemplo:
char *p;
p=malloc(1000);
— O trecho acima aloca 1000 bytes de memória para o 
armazenamento de caracteres.
215
Malloc (cont)
— Porém:
— A memória ocupada por um determinado tipo pode variar de 
máquina para máquina!
— As implementações devem ser independentes da máquina!
— Solução: 
— usar o operador sizeof:
int *p;
p=malloc(50*sizeof(int));
— Aloca memória suficiente para armazenar 50 inteiros (de maneira 
contígua na memória)
216
Malloc (cont)
— Porém, pode ser que o programa tenha alocado muita memória, a ponto 
de não restar espaço na área de heap (efetivamente, isto pode ocorrer);
— Se malloc não conseguir alocar memória, ele retornará um ponteiro nulo;
— Logo, é preciso testar o resultado de malloc:
char *p;
if( (p=malloc( 50*sizeof(char) ) ) == NULL ) {
 printf("Não foi possivel alocar memoria\n");
 exit(1);
}
217
Free
— Libera memória previamente alocada de maneira dinâmica, por 
meio de uma das funções de alocação dinâmica (devolve memória 
ao "heap")
— Recebe como argumento um ponteiro para a porção de memória 
que se deseja liberar
— Jamais use free com um argumento inválido, pois isto destrói a lista 
de memória livre!!
free(p);
218
EX
EM
P
LO
#include <stdio.h>
#include <stdlib.h>
main () {
 int n, i, *p, *inicio;
 printf ("Entre com o numero de elementos: \n");
 scanf ("%d", &n);
 if ((p = malloc (n * sizeof (int))) == NULL) {
 printf ("Não foi possível alocar memória\n");
 exit (1);
 }
 inicio = p;
 for (i = 0; i < n; i++, p++) {
 printf ("Entre com o %d valor: \n", i + 1);
 scanf ("%d", p);
 }
 p = inicio;
 for (i = 0; i < n; i++, p++) {
 printf ("%do. valor: %d\n", i + 1, *p);
 }
}
219
EX
EM
P
LO
#include <stdio.h>
#include <stdlib.h>
main()
{
int n, novo_n, adic, i, *p, *inicio;
printf("Entre com o numero de elementos: \n");
scanf("%d", &n);
if ((p = malloc(n * sizeof(int))) == NULL) {
printf("Não foi possível alocar memória\n");
exit(1);
}
inicio = p;
for (i = 0; i < n; i++, p++) {
printf("Entre com o %d valor: \n", i + 1);
scanf("%d", p);
}
p = inicio;
for (i = 0; i < n; i++, p++) {
printf("%do. valor: %d\n", i + 1, *p);
}
Exemplo de realloc
220
EX
EM
P
LO
printf("Entre com a quantidade de elementos adicionais: \n");
scanf("%d", &adic);
novo_n = adic + n;
p = inicio;
p = realloc(p, (novo_n));
inicio = p;
for (i = n; i < novo_n; i++) {
printf("Entre com o %d valor: \n", i + 1);
scanf("%d", &p[i]);
}
p = inicio;
for (i = 0; i < novo_n; i++, p++) {
printf("%do. valor: %d\n", i + 1, *p);
}
}
221
EX
ER
C
ÍC
IO
S
1) Modifique o programa do slide 160, de modo a substituir a 
alocação estática das estruturas envolvidas pela alocação dinâmica
222
LISTAS ENCADEADAS
223
Conceito
— Uma lista encadeada é uma representação de uma sequência de 
objetos na memória do computador. Cada elemento da sequência é 
armazenado em uma célula da lista: o primeiro elemento na 
primeira célula, o segundo na segunda e assim por diante. 
224
Estrutura de uma lista encadeada
— Uma lista encadeada (linked list) é uma sequência de células; cada célula 
contém um objeto de algum tipo e o endereço da célula seguinte. 
— Por exemplo, os objetos armazenados nas células são do tipo int. A 
estrutura de cada célula de uma tal lista pode ser definida assim:
 
struct cel {
 int conteudo;
 struct cel *prox;
 }; conteudo prox
225
Estrutura de uma lista encadeada (cont.)
— Por conveniência,definiremos o tipo celula:
typedef struct cel celula;
— Uma célula c e um ponteiro p para uma célula podem ser declarados assim:
celula c;
celula *p;
— Se c é uma célula então c.conteudo é o conteúdo da célula e c.prox é o endereço da 
próxima célula. 
— Se p é o endereço de uma célula, então p->conteudo é o conteúdo da célula e p->prox é 
o endereço da próxima célula. 
— Se p é o endereço da última célula da lista então p->prox vale NULL . 
/
226
Listas com (e sem) cabeça
— Uma lista encadeada pode ser organizada de duas maneiras diferentes:
— Lista com cabeça: O conteúdo da primeira célula é irrelevante servindo apenas para marcar o início 
da lista. A primeira célula é a cabeça (head cell) da lista. A primeira célula está sempre no mesmo 
lugar na memória, mesmo que a lista fique vazia. Digamos que ini é o endereço da primeira célula. 
Então ini->prox == NULL se e somente se a lista está vazia. Para criar uma lista vazia, basta:
 celula *ini;
 ini = malloc( sizeof (celula));
 ini->prox = NULL;
— Lista sem cabeça: O conteúdo da primeira célula é tão relevante quanto o das demais. Nesse caso, a 
lista está vazia se o endereço de sua primeira célula é NULL. Para criar uma lista vazia basta:
 celula *ini; 
 ini = NULL;
227
EX
EM
P
LO
//Imprime o conteúdo de uma lista encadeada com cabeça
void imprima( celula *ini)
{
 celula *p;
 for (p = ini->prox; p != NULL; p = p->prox) 
 printf( "%d\n", p->conteudo);
}
//Imprime o conteúdo de uma lista encadeada sem cabeça
void imprima( celula *ini)
{
 celula *p;
 for (p = ini; p != NULL; p = p->prox) 
 printf( "%d\n", p->conteudo);
}
228
EX
EM
P
LO
//Busca iterativa
celula *busca( int x, celula *ini)
{
 celula *p;
 p = ini->prox;
 while (p != NULL && p->conteudo != x) 
 p = p->prox; 
 return p; 
}
//Busca recursiva
celula *busca2( int x, celula *ini)
{
 if (ini->prox == NULL) 
 return NULL;
 if (ini->prox->conteudo == x) 
 return ini->prox;
 return busca2( x, ini->prox);
}
229
Inserção em uma lista
— Para inserir (insert) uma nova célula com conteúdo x entre a posição 
apontada por p e a posição seguinte em uma lista encadeada:
void insere( int x, celula *p)
{
 celula *nova;
 nova = malloc( sizeof (celula));
 nova->conteudo = x;
 nova->prox = p->prox;
 p->prox = nova;
}
230
Remoção em uma lista
— Para remover uma certa célula da lista, a ideia mais óbvia, que é apontar para a célula que se 
remover, claramente não é boa. É melhor apontar para a célula anterior à que se quer remover. 
— Supondo que p é o endereço de uma célula de uma lista com cabeça e que se deseja remover a 
célula apontada por p->prox. (Note que a função de remoção não precisa saber onde a lista 
começa)
void remove( celula *p)
{
 celula *morta;
 morta = p->prox;
 p->prox = morta->prox;
 free( morta);
}
231
EX
EM
P
LO
#include<stdio.h>
#include<stdlib.h>
struct cel {
int conteudo;
struct cel *prox;
};
typedef struct cel celula;
void insere (int x, celula * p);
void imprime (celula * ini);
celula *busca(int x, celula * ini);
celula *cria(void);
void remova (int y, celula * ini);
void remova_end(celula * p);
232
EX
EM
P
LO
int
main()
{
celula *ini, *pos;
ini = cria();
insere(10, ini);
insere(100, ini);
insere(1000, ini);
imprime(ini);
pos = busca(100, ini);
insere(99, pos);
imprime(ini);
remova(99, ini);
imprime(ini);
pos = busca(100, ini);
remova_end(pos);
imprime(ini);
return 0;
}
233
EX
EM
P
LO
celula *cria(void)
{
celula *start;
start = malloc(sizeof(celula));
start->prox = NULL;
return start;
}
void insere(int x, celula * p)
{
celula *nova;
nova = malloc(sizeof(celula));
nova->conteudo = x;
nova->prox = p->prox;
p->prox = nova;
}
void imprime(celula * ini)
{
celula *p;
for (p = ini->prox; p != NULL; p = p->prox)
printf("%d\n", p->conteudo);
}
234
EX
EM
P
LO
celula *busca(int x, celula * ini)
{
celula *p;
p = ini->prox;
while (p != NULL && p->conteudo != x)
p = p->prox;
return p;
}
void remova(int y, celula * ini)
{
celula *p, *q;
p = ini;
q = ini->prox;
while ((q != NULL) && (q->conteudo != y)) {
p = q;
q = q->prox;
}
if (q != NULL) {
p->prox = q->prox;
free(q);
}
}
void remova_end(celula * p)
{
celula *morta;
morta = p->prox;
p->prox = morta->prox;
free(morta);
}
235
EX
ER
C
ÍC
IO
S
1) Modifique o programa do slide 160, de modo a alocar 
dinamicamente numa lista encadeada os dados daquela estrutura.
	Slide 1
	Slide 2
	Slide 3
	Slide 4
	Slide 5
	Slide 6
	Slide 7
	Slide 8
	Slide 9
	Slide 10
	Slide 11
	Slide 12
	Slide 13
	Slide 14
	Slide 15
	Slide 16
	Slide 17
	Slide 18
	Slide 19
	Slide 20
	Slide 21
	Slide 22
	Slide 23
	Slide 24
	Slide 25
	Slide 26
	Slide 27
	Slide 28
	Slide 29
	Slide 30
	Slide 31
	Slide 32
	Slide 33
	Slide 34
	Slide 35
	Slide 36
	Slide 37
	Slide 38
	Slide 39
	Slide 40
	Slide 41
	Slide 42
	Slide 43
	Slide 44
	Slide 45
	Slide 46
	Slide 47
	Slide 48
	Slide 49
	Slide 50
	Slide 51
	Slide 52
	Slide 53
	Slide 54
	Slide 55
	Slide 56
	Slide 57
	Slide 58
	Slide 59
	Slide 60
	Slide 61
	Slide 62
	Slide 63
	Slide 64
	Slide 65
	Slide 66
	Slide 67
	Slide 68
	Slide 69
	Slide 70
	Slide 71
	Slide 72
	Slide 73
	Slide 74
	Slide 75
	Slide 76
	Slide 77
	Slide 78
	Slide 79
	Slide 80
	Slide 81
	Slide 82
	Slide 83
	Slide 84
	Slide 85
	Slide 86
	Slide 87
	Slide 88
	Slide 89
	Slide 90
	Slide 91
	Slide 92
	Slide 93
	Slide 94
	Slide 95
	Slide 96
	Slide 97
	Slide 98
	Slide 99
	Slide 100
	Slide 101
	Slide 102
	Slide 103
	Slide 104
	Slide 105
	Slide 106
	Slide 107
	Slide 108
	Slide 109
	Slide 110
	Slide 111
	Slide 112
	Slide 113
	Slide 114
	Slide 115
	Slide 116
	Slide 117
	Slide 118
	Slide 119
	Slide 120
	Slide 121
	Slide 122
	Slide 123
	Slide 124
	Slide 125
	Slide 126
	Slide 127
	Slide 128
	Slide 129
	Slide 130
	Slide 131
	Slide 132
	Slide 133
	Slide 134
	Slide 135
	Slide 136
	Slide 137
	Slide 138
	Slide 139
	Slide 140
	Slide 141
	Slide 142
	Slide 143
	Slide 144
	Slide 145
	Slide 146
	Slide 147
	Slide 148
	Slide 149
	Slide 150
	Slide 151
	Slide 152
	Slide 153
	Slide 154
	Slide 155
	Slide 156
	Slide 157
	Slide 158
	Slide 159
	Slide 160
	Slide 161
	Slide 162
	Slide 163
	Slide 164
	Slide 165
	Slide 166
	Slide 167
	Slide 168
	Slide 169
	Slide 170
	Slide 171
	Slide 172
	Slide 173
	Slide 174
	Slide 175
	Slide 176
	Slide 177
	Slide 178
	Slide 179
	Slide 180
	Slide 181
	Slide 182
	Slide 183
	Slide 184
	Slide 185
	Slide 186
	Slide 187
	Slide 188
	Slide 189
	Slide 190
	Slide 191
	Slide 192
	Slide 193
	Slide 194
	Slide 195
	Slide 196
	Slide 197
	Slide 198
	Slide 199
	Slide 200
	Slide 201
	Slide 202
	Slide 203
	Slide 204
	Slide 205
	Slide 206
	Slide 207
	Slide 208
	Slide 209
	Slide 210
	Slide 211
	Slide 212
	Slide 213
	Slide 214
	Slide 215
	Slide 216
	Slide 217
	Slide 218
	Slide 219
	Slide 220
	Slide 221
	Slide 222
	Slide 223
	Slide 224
	Slide 225
	Slide 226
	Slide 227
	Slide 228
	Slide 229
	Slide 230
	Slide 231
	Slide 232
	Slide 233
	Slide 234
	Slide 235

Mais conteúdos dessa disciplina