Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.
details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

details

Libere esse material sem enrolação!

Craque NetoCraque Neto

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

Prévia do material em texto

DEPARTAMENTO DE INFORMÁTICA 
 
 
 
 
 
 
 
 
Programação 
Estruturada 
 
 
Notas de aula 
 
Profa. Beatriz Lux 
Prof. Rolf Fredi Molz 
 
Atualizada em fevereiro 2017 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
1 
 
 
 Sumário 
 
 
2.0 Bibliografia recomendada 
 
2 
 
3.0 Conceitos Gerais 
 
3 
 
4.0 Comandos de controle de fluxo 
 
17 
 
5.0 Tipo Ponteiro 
 
24 
 
6.0 Modularização 
 
33 
 
7.0 Tipo estruturado homogêneo - matrizes 
 
47 
 
8.0 Strings em C 
 
57 
 
9.0 Tipo estruturado heterogêneo - registros 
 
62 
 
10.0 Métodos internos de ordenação 
 
70 
 
11.0 Métodos internos de pesquisa 
 
77 
 
12.0 Recursividade 
 
79 
 
13.0 Operações em meio magnético - arquivos 
 
82 
 
14.0 Estruturas e alocação dinâmica de memória – exemplo com 
Lista Encadeada 
 
94 
 
15.0 Anexo – Como adicionar um arquivo Header a um projeto 
 
16.0 Anexo – Tabela ascii 
 
99 
 
 101 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
2 
 
2.0 Bibliografia Recomendada 
 
Recomenda-se ao aluno não basear seu estudo apenas no conteúdo destas notas 
de aula, sendo importante que busque mais informações através da leitura de livros 
dedicados ao estudo de programação estruturada e da linguagem C. Abaixo cita-
mos alguns títulos que consideramos apropriados e que nortearam a produção des-
tas notas de aula. Ambos podem ser encontrados na nossa biblioteca: 
 
SCHILDT, Herbert. C : completo e total. 3. ed., rev. e atual. São Paulo: Makron, 
c1997. 
 
MIZRAHI, Victorine Viviane. Treinamento em linguagem C. Volume 1. São 
Paulo: Makron, 1990. 
 
MIZRAHI, Victorine Viviane. Treinamento em linguagem C. Volume 2. São 
Paulo: Makron, 1990. 
 
ZIVIANI, Nivio. Projeto de algoritmos com implementações em Pascal e C. São 
Paulo: Pioneira, 1999. 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
3 
 
3.0 Conceitos Gerais 
 
3.1 Objetivos e Caracterização da Linguagem 
 
A linguagem de programação C foi criada por Dennis Richtie,no início da década 
de 70, nos laboratórios Bell para ser usada na implementação de sistemas opera-
cionais (UNIX) e outras tarefas de programação de baixo nível. 
A linguagem era fornecida junto com o UNIX e manteve sua sintaxe padrão inalte-
rada por cerca de dez anos. A principal documentação deste padrão encontra-se 
na publicação "The C Programming Language", de Brian Kernighan e Dennis 
Ritchie (K&R), tida como a "bíblia da linguagem C". 
Em 1985, ANSI (American National Standards Institute) estabeleceu um padrão 
oficial de C, o chamado "C ANSI". Um dos objetivos do processo de padronização 
C ANSI foi o de produzir um sobreconjunto do C K&R, incorporando muitas das 
características não-oficiais subseqüentemente introduzidas. 
C caracteriza-se por ser uma linguagem estruturada, pois possibilita dividir a infor-
mação em blocos estanques, o que é feito através de subprogramas (funções), que 
são os blocos fundamentais de um programa em C. Desta maneira, determinada 
tarefa pode ser definida e escrita em separado, numa função, utilizando suas pró-
prias variáveis (chamadas locais) de cuja existência, não precisará tomar conheci-
mento o resto do programa ou os demais subprogramas. Este conceito é um dos 
tópicos que estudaremos com profundidade em nossa disciplina. 
 
Outra característica de C é sua portabilidade, ou seja, um código escrito em 
linguagem C poderá ser executado em diferentes máquinas, independentemente 
da sua configuração física e do sistema operacional residente, sendo apenas 
necessário sua re-compilação para cada arquitetura diferente 
A Linguagem C tornou-se ao longo do tempo uma das linguagens de programação 
mais usadas, pois, afora as qualidades acima citadas, possibilita produzir códigos 
concisos e de rápido processamento por ser uma linguagem de nível médio, onde 
estão combinados elementos de linguagens de alto nível e as funcionalidades de 
assembly. Foi utilizada na criação e desenvolvimento de softwares e sistemas ope-
racionais que se tornaram famosos em todo mundo, como por exemplo o Sistema 
Operacional Windows. 
 
 
 
3.2 Elementos Básicos da Linguagem 
 
3.1 Símbolos usados 
 
 Letras de A a Z tanto maiúsculas como minúsculas. 
 
 O símbolo _ (caracter de sublinha) é considerado letra. 
 
 Digitos de 0 a 9. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
4 
 
 
 Especiais + - * / = ^ # & , : ; ‘ $ e outros 
 
 Símbolos especiais usados em conjunto: 
 = atribuição 
 != diferente 
 <= menor ou igual 
 >= maior ou igual 
 { } delimitadores de inicio e fim de um bloco de comandos 
 /* inicio de comentário 
 */ fim de comentário 
// inicio de comentário de aoenas 1 linha (não é necessário fechá-lo) 
 
 O tamanho máximo de uma linha é de 127 caracteres. 
 
 
3.2 Tipos Básicos de Dados 
 
Todas as vaiáveis em C possuem um identificador (nome) e um tipo, que especifica 
os valores que a variável poderá assumir. A tabela 1 apresenta o s cinco tipos bá-
sicos, o número de bits que cada um utiliza e a faixa e valores que alcança. 
 
Tipo Bits Faixa de valores 
char 8 -128 à 127 
int 16 -32768 à 32767 
float 32 -3.4E-38 à 3.4E+38 
double 64 -1.7E-308 à 1.7E+308 
void 0 Sem valor 
Tabela 1 
 
 
3.3 Identificadores 
Os identificadores, que servem para nomear programas, variáveis, constantes, pro-
cedimentos, etc., seguem a seguinte regra: 
 
Devem iniciar por uma letra e a esta podem seguir letras, números ou sinal 
de sublinha. Não pode conter espaços. Tamanho: até 127 caracteres, sendo 
significativos os 32 primeiros. Obs.: atentar para as palavras reservadas 
da linguagem que não podem ser usadas. 
 
Em C os primeiros 32 caracteres de um nome de identificador são significan-
tes. Isso quer dizer que duas variáveis com os 32 primeiros caracteres em 
comum, diferindo somente no 33º , são consideradas iguais. 
A linguagem C é case-sensitive , o que significa que letras maiúsculas e mi-
núsculas são tratadas como diferentes umas das outras. Por isso, media, Me-
dia e MEDia são distintos. 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
5 
 
3.4 Palavras reservadas da linguagem 
A tabela 2 apresenta as palavras reservadas da linguagem C, que não poderão ser 
utilizadas como identificadores. 
 
auto double if static 
break else int struct 
case entry long switch 
char extern register typedef 
continue float return union 
default for sizeof unsigned 
do goto short while 
Tabela 2 
 
 
3.5 Estrutura básica de um Programa em C 
 
Os programas em C são formados por uma ou mais funções, porém sempre haverá 
uma (e só uma) função denominada main, onde a execução do programa neces-
sariamente irá começar. Além da main poderá haver outras funções, dependendo 
apenas de como o programador dividir as tarefas que seu programa deverá realizar. 
 
Exemplo de um programa simples em C: 
 
#include<stdio.h> //inclusão de biblioteca 
#include<math.h> //inclusão de biblioteca 
#define v 3.0 // definição de contante 
int main() 
{ float a,r,q; // declaração de variáveis 
 printf("Informe um real\n"); //apresentação de dados na tela 
 scanf("%f",&a); //entrada de dados via teclado 
 printf("O no.lido foi: %.2f\n", a); 
 r=sqrt(a); 
 printf("raiz quadrada de %.2f: %.2f\n",a,r); 
 q=pow(a,2); 
 printf("%.2f ao quadrado: %.2f\n",a,q); 
 printf("%.2f ao quadrado: %.2f",v,pow(v,2)); 
 return 0; //retorno da função main 
} 
 
Tela de entrada e saída do programa quando executado (F9): 
 
 
3.5.1 Diretiva #include 
Toda a diretiva, em C, começa com o símbolo # no início da linha. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
6 
 
A diretiva #include inclui o conteúdo de um outro arquivo dentro do programa 
atual, ou seja, a linha que contêm a diretiva é substituída pelo conteúdo do ar-
quivo especificado. 
No programa exemplo acima necessitamos incluir alguns arquivos que contêm a 
declaração de funções de bibliotecas padrão. As bibliotecas, normalmente, pos-
suem a extensão .h e se encontram em algum diretório pré-definido pelo compila-
dor. Sempre que o programa utilizar alguma função da biblioteca-padrão deve ser 
incluído o arquivo correspondente. 
Apresenta-se a seguir alguns dos principais .h da linguagem C: Descrição 
stdio.h - Funções de entrada e saída (I/O) 
string.h - Funções de tratamento de strings 
math.h - Funções matemáticas 
ctype.h - Funções de teste e tratamento de caracteres 
stdlib.h - Funções de uso genérico 
É importante saber que cada diretiva deve estar em sua própria linha. 
 
3.5.2 – Definição de Constantes 
O conceito de constantes em linguagens de programação é atribuir um certo valor 
constante (que não pode ser alterado) a um nome, e quando este nome for refe-
renciado dentro do código do programa, será utilizado nas operações o valor atri-
buído a este nome. 
Uma das formas de definirmos constantes em C é utilizar a diretiva #define que 
é conhecida como diretiva de macro-substituição. 
 
Conforme o tipo da constante, será sua representação: 
 
 Constantes de caractere são envolvidas por aspas simples (‘’); 
 Ex; ‘a’ 
 Constantes formadas por cadeia de caracteres são envolvidas por aspas du-
plas; 
Ex: “Tecle algo para sair do programa” 
 Constantes com valor inteiro são representadas por um número inteiro; 
Ex: 10, -100 
 Constantes com valor real (float) devem apresentar o ponto decimal seguido 
da parte fracionária do número; 
Ex: 19.55 
 
# define nome “João” 
# define pi 3.1416 
# define letra ´a´ 
 
O compilador substitui o identificador pelo valor cada vez que aquele for encontrado 
no programa fonte antes da compilação do programa. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
7 
 
É recomendável o uso de identificadores como sinônimos de constantes pois au-
menta a legibilidade do programa e auxilia sua documentação, além disto, o agru-
pamento das constantes no início do programa torna mais fácil a sua modificação, 
caso necessário. 
 
3.5.3 Comentários 
É bastante útil e indicado colocar comentários nos códigos de programas para fa-
cilitar sua leitura e elucidar seu objetivo e funcionamento . 
 
Utiliza-se caracteres especiais para indicar comentários: 
 comentários de uma linha podem ser iniciados com duas barras ( // ) 
 comentários de mais de uma linha iniciam com uma sequencia dos carac-
teres barra asterisco ( /* ) e encerrados com asterisco barra ( */ ) 
 
 
3.5.4 Declaração e variáveis 
Todas as variáveis de um programa deverão ser declaradas. 
Para declarar uma variável devemos identificador inicialmente seu tipo, a seguir 
o nome da variável e encerrar a declaração com ponto e vírgula. 
 
float raio; 
int idade; 
 
Se tivermos mais de uma variável com o mesmo tipo, podem ser declaradas na 
mesma linha, separadas por vírgula. 
float raio, área; 
 
As variáveis são classificadas em variáveis locais e globais. 
Variáveis globais são aquelas declaradas fora do escopo das funções. 
Variáveis locais são aquelas declaradas no início de um bloco e seus escopos 
estão restritos aos blocos em que foram declaradas. A tabela 2 exemplifica as duas 
formas de declaração, local e global. 
 
#include<stdio.h> 
#include<math.h> 
#define v 3.0 
float a,r,q; 
 
int main() 
{ 
printf("Informe um real\n"); 
scanf("%f",&a); 
printf("O no.lido foi: %.2f\n ", 
a); 
r=sqrt(a); 
printf("raiz quadrada de %.2f: 
%.2f\n", a,r); 
 return 0; 
} 
#include<stdio.h> 
#include<math.h> 
#define v 3.0 
 
 
int main() 
{float a,r,q; 
printf("Informe um real\n"); 
scanf("%f",&a); 
printf("O no.lido foi: %.2f\n ", 
a); 
r=sqrt(a); 
printf("raiz quadrada de %.2f: 
%.2f\n", a,r); 
 return 0; 
} 
 
Exemplo variável global Exemplo variável local 
Tabela 2 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
8 
 
 
Observações: 
 É uma prática tradicional do C, usar letras minúsculas para nomes de 
variáveis e maiúsculas para nomes de constantes. Isto facilita na hora 
da leitura do código; 
 Quando se escreve código usando nomes de variáveis em português, 
evita-se possíveis conflitos com nomes de rotinas encontrados nas di-
versas bibliotecas, que são em sua maioria absoluta, palavras em in-
glês. 
 
 
3.5.4 A função principal 
 
A linha int main() indica que estamos definindo uma função de nome main. To-
dos os programas em C devem ter uma função main, pois é esta função que será 
chamada quando o programa for executado. 
 
O conteúdo da função é delimitado por chaves { }, obrigatoriamente. 
Isso significa que { (abre chaves) substitui a palavra inicio que utilizamos em algo-
ritmos e } (fecha chaves) substitui a palavra fim. 
O código que estiver dentro das chaves será executado seqüencialmente quando 
a função for chamada. 
 
Em C, sempre que necessitarmos delimitar um bloco de comandos que deve ser 
executado sequencialmente, utilizamos as chaves, isto se tornará novamente re-
levante quando estudarmos o uso dos comando condicionais e de repetição. 
 
 
3.5.5 O uso do ponto e vírgula 
 
É importante notar no exemplo que todas as linhas de comando são separadas 
por ponto e vírgula, exceto as declarações #include, #define, o cabeçalho da fun-
ção e os demarcadores de blocos (chaves) de instruções. 
Durante a compilação do programa, o ponto-e-vírgula mostra ao compilador quando 
uma linha de comando termina e quando outra linha de comando se inicia. 
Assim, o compilador acusará um erro sempre que verificar a falta de um ponto-e-
vírgula, pois ele não saberá quando termina ou começa um determinado comando 
dentro do código digitado. 
 
3.5.6 Operador de atribuição 
O operador “=” atribui um valor ou resultado de uma expressão contida a sua direita 
para a variável (ou constante) especificada a sua esquerda. 
Exemplos: 
a=V*2; 
b=c*valor+sqrt(x); 
 
É possível fazer atribuição sucessiva de valores: a=b=c=1; 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
9 
 
É possível atribuir um valor a uma variável ao mesmo tempo em que ela é decla-
rada. 
int a=5,b=2; 
float r=8.6; 
 
 
3.5.7 Expressões, Operadores e funções aritméticas 
 
 Expressões são algoritmos especificados para a computação de valores, consis-
tem em operações com variáveis, constantes e funções combinadas com opera-
dores. 
 a=v*2; c=a+b; c=a/d; 
 
3.5.7.1 Operadores Aritméticos 
Veja na tabela 3 os operadores aritméticos 
 
Operador Ação 
+ Soma (inteira e ponto flutuante) 
- Subtração ou Troca de sinal (inteira e ponto flutuante) 
* Multiplicação (inteira e ponto flutuante) 
/ Divisão (inteira e ponto flutuante) 
% Resto de divisão (de inteiros) 
-- Decremento 
++ Incremento 
Tabela 3O operador / (divisão) 
 quando aplicado a variáveis inteiras, fornece o resultado da divisão inteira; 
 quando aplicado a variáveis em ponto flutuante fornece o resultado da divi-
são "real". 
O operador % fornece o resto da divisão inteira entre dois inteiros. 
 Exemplo: 
 int a ,b, x, y; 
 float z , z1, z2; 
 { a=17; 
b=3; 
z=17.0 
 x = a / b; 
 y = a % b; 
 z1 = z / b; 
 z2 = a/b; 
 } 
ao final da execução destas linhas, os valores calculados seriam 
 x = 5 y = 2 z1 = 5.666666 z2 = 5.0 . 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
10 
 
Note que, na linha correspondente a z2, primeiramente é feita uma divisão inteira 
(pois os dois operandos são inteiros). Somente após efetuada a divisão é que o 
resultado é atribuído a uma variável float. 
 
3.5.7.2- Funções Aritméticas Pré-Definidas 
 
São funções implementadas na biblioteca math.h. 
Na tabela 4 são apresentadas algumas funções matemáticas em C 
 
resultado função tipo do pa-
râmetro 
tipo do re-
sultado 
Logaritmo neperiano log(x) real real 
Logaritmo base 10 log10(x) 
 
real real 
e elevado à potencia x exp(x) real real 
Valor absoluto de x fabs(x) real real 
abs(x) int int 
Decompõe um real x em duas partes: 
y recebe a parte inteira e a função devolve 
a parte fracionária, ambas como real (dou-
ble) 
 
modf(x,y) real, real real 
Arredonda o valor de x para cima ceil (x) real real 
Arredonda o valor de x para baixo floor(x) real real 
Retorna x elevado a potência y pow(x,y) real real 
Raiz quadrada de x sqrt(x ) real real 
Retorna o resto da divisão de x por y 
Ex: fmod (25.55 , 2) = 1.55 
fmod(x,y) real, real real 
Seno de x sin(x ) real real 
Cosseno de x cos( x) real real 
Arco-tangente de x atan( x) real real 
Tabela 4 
 
A ativação da função no programa é feita através do identificador, nome da função 
e da lista de argumentos (parâmetros), entre parênteses e separados por vírgula.
 
Obs. : x é o argumento da função, pode ser uma expressão aritmética. 
 
 
 
3.5.7.3 Operadores Relacionais 
 
Uma relação é uma comparação realizada entre valores do mesmo tipo. Estes va-
lores são representados na relação por constantes, variáveis ou expressões. O re-
sultado será sempre True ou False. A natureza da relação é indicada por um ope-
rador relacional, descrito na tabela 5. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
11 
 
 
 
Operador Ação 
> Maior do que 
>= Maior ou igual a 
< Menor do que 
<= Menor ou igual a 
== Igual a 
!= Diferente de 
Tabela 5 
 
 
3.5.7.4 Operador ternário 
 
Em C podemos expressar relações de uma forma bastante compacta, através do 
uso do operador ternário, que serve para substitui o comando if-else. 
 
Como exemplo, na coluna 1 da tabela 6 é apresentada uma construção condicional 
com o comando if–else e na coluna 2 a sua correspondente com comando ternário. 
 
If (n1>n2) 
 maior= n1 
else 
 maior=n2 
maior=(n1>n2) ? n1 : n2 
Tabela 6 
 
Fica definido na construção que aparece na segunda coluna que haverá uma ava-
liação da expressão lógica e que se resultar verdadeira deverá ser atribuido o valor 
de n1 à variavel maior, se resultar falsa, a variável maior receberá o valor de n2. 
 
Forma geral do operador ternário: 
 
 condição ? expressão_1 : expressão_2 
 
 
 
3.5.7.5 Operadores Lógicos 
Os operadores lógicos em C são descritos na tabela 7 
 
 
Operador Ação 
&& E 
|| OU 
! NÃO 
Tabela 7 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
12 
 
 
3.5.7.6 Operadores de Atribuição Composta 
 
Em C qualquer expressão da forma: 
 
 variável = variável operador expressão 
 
pode ser escrita como: 
 variável operador = expressão 
 
 
Exemplos: 
raiz = raiz * 4; raiz *= 4; 
ano = ano + 10; ano += 10; 
soma = soma / ( a + b); soma /= (a + b); 
i = i % 2; i %= 2; 
 
A tabela 8 mostra que diferentes posicionamentos dos operadores resultados origi-
nam diferentes resultados. 
 
x=10; 
y=++x; y recebe 11 e x recebe 11 
x=10; 
y=x++; y recebe 10 e x recebe 11 
 
int a,b,c,i=3; a:? b:? c:? i:3 
a=i++; a:3 b:? c:? i:4 
b=++i; a:3 b:5 c:? i:5 
c=--i; a:3 b:5 c:4 i:4 
Tabela 8 
 
 
3.5.7.7 Conversão entre tipos de variáveis - type casting 
 
O C permite a mudança de tipo das suas variáveis através do operador (cast), onde 
cast é o novo tipo pretendido. 
O casting pode ser usado com qualquer um dos tipos simples. 
Exemplo: 
 
int k; 
char ch = 'A'; 
k = (int) ch; 
 
Aqui o valor de k será 65 (o código ascii do carácter 'A'). 
 
Um uso freqüente do casting é assegurar que a divisão entre inteiros não seja uma 
divisão inteira. Basta para isso converter para real o numerador ou denominador. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
13 
 
O outro operando é assim também automaticamente convertido, antes de se efe-
tuar a operação. 
 
 
3.5.7.8 Operador unário sizeof() 
 
O operador sizeof()retorna o tamanho em bytes da expressão ou tipo fornecido 
entre parênteses Por exemplo, suponha que o tipo float tenha quatro bytes então 
o operador sizeof(float) retorna o valor 4. 
 
 
 
3.6 Funções de entrada e saída de dados 
 
3.6.1 Função de saída de dados formatada 
 
Forma Geral: 
printf (“expressão de controle”, lista de argumentos); 
 
Esta função permite escrever na tela e é um comando da biblioteca stdio.h 
A expressão de controle pode conter caracteres que serão exibidos na tela e os 
códigos de formatação (ou controle) que indicam o formato em que os argumentos 
deverão ser impressos. 
Cada argumento deve ser separado por vírgula. Os códigos de controle usam a 
notação % para formatar variáveis e \ para formatar a disposição na tela (quebra 
de linha, tabulação, etc). Para cada formatação de variável na expressão de con-
trole deve haver uma variável na lista de argumentos. 
Exemplo: 
printf("O MDC entre %d e %d eh: %d\n",m,n,x); 
 
A tabela 9 apresenta códigos de controle para formatar variáveis: 
 
 
Código Significado 
%d inteiro 
%f float 
%lf double 
%c 1 caractere 
%s String 
%p ponteiro 
%% Coloca na tela um % 
Tabela 9 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
14 
 
A tabela 10 apresenta os códigos de controle para disposição na tela 
 
Código Significado 
\b Retrocesso ("back") 
\f Alimentação de formulário ("form feed") 
\n Nova linha ("new line") 
\t Tabulação horizontal ("tab") 
\" Aspas 
\' Apóstrofo 
\0 Nulo (0 em decimal) 
\\ Barra invertida 
\v Tabulação vertical 
\a Sinal sonoro ("beep") 
\N Constante octal (N é o valor da constante) 
\xN Constante hexadecimal (N é o valor da constante) 
Tabela 10 
Na lista de argumentos pode haver variáveis e/ou constantes, sempre separadas 
por vírgula, veja o exemplo do trecho de programa abaixo: 
int p 
p= 65487 * 236597 ; 
printf("O Produto entre %d e %d eh: %d\n",65487, 236597 ,p); 
 
A função printf(): 
 Imprime a partir do último caracter impresso.• 
 Não muda de linha até que a linha acabe ou que encontre um \n. 
 
Alguns exemplos de printf() e o que eles exibem: 
printf ("Teste %% %%") -> "Teste % %" 
printf ("%f",40.345) -> "40.345" 
printf ("Um caractere %c e um inteiro %d",'D',120) -> "Um carac-
tere D e um inteiro 120" 
printf ("%s e um exemplo","Este")-> "Este e um exemplo" 
printf ("%s%d%%","Juros de ",10) -> "Juros de 10%" 
 
Ao apresentar na tela valores com ponto flutuante, estes serão colocados em nota-
ção científica. Se quisermos apresentar os valores com casas decimais é necessá-
rio acrescentar um formato, como no exemplo abaixo: 
 
#include <stdio.h> 
#define V 3 
int a; 
float b; 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
15 
 
int main() 
{ a=V*2; 
 b=sqrt(a); 
 printf(" %d %5.2f ",a,b); 
 return 0; 
 } 
 
Através desta especificação de formato ( printf(" %d %5.2f ",a,b), o valor de b será 
escrito com 5 caracteres no total (incluindo o ponto da casa decimal) e duas ca-
sas depois do ponto decimal. 
A tabela 11 apresenta mais exemplos: 
 
Código Descrição 
%6f Ponto flutuante com pelo menos seis caracteres 
%.2f Ponto flutuante com dois caracteres após o ponto decimal 
%6.2f Ponto flutuante com pelo menos seis caracteres e dois após o ponto 
decimal 
%6d Inteiro com pelo menos seis caracteres 
Tabela 11 
 
 
3.6.2 Função de entrada de dados formatada 
 
Permitem ler dados pelo teclado. Sua sintaxe é semelhante ao printf: 
Forma Geral : scanf(“expressão de controle”, lista de argumentos); 
 
A expressão de controle pode conter códigos de formatação, precedidos por %. 
 
A lista de argumentos: 
 Depende da String de Formato. 
 Separados por ‘,’. 
 Sempre variáveis. 
 As variáveis devem ser precedidas por ‘&’ 
 
Exemplo: 
int mat; 
float media; 
int main () 
{ printf(“Entre com a matrícula do aluno e sua media: "); 
 scanf(“%d %f“, &mat, &media); 
-------; 
--------; 
} 
 %f indica que será lido um valor do tipo float, atribuído a uma variável na 
sequencia indicada na lista de argumentos (&media). 
 A lista de argumentos consiste então no endereço das variáveis. 
 C oferece um operador para tipos básicos chamado operador de endereço 
&, que retorna o endereço do operando. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
16 
 
Exemplo para o operador de endereços: 
 
int main() 
 { 
 int num; 
 num = 2; 
 printf (“Valor %d, endereço = %u”, num, &num); 
 return 0; 
 } 
 
O programa acima imprime o valor e o endereço de memória da variável num. 
%u é usado pois endereço é visto como inteiro sem sinal. 
Ex. de saída: Valor=2, endereço = 1370 
 
 
3.6.3 Funções de Entrada e Saída de dados para caracteres 
 
3.6.3.1 Funções de Entrada e Saída para caracteres (com enter) 
 
getchar() 
Biblioteca: stdio.h 
Declaração: int getchar(void); 
Propósito: A função getchar() (get character) lê um caracter individual da entrada 
padrão (em geral, o teclado). 
Esta função é dita line buffered, isto é, não retorna valores até que o caracter de 
controle line feed (\n) seja lido. Este caracter, normalmente, é enviado pelo teclado 
quando a tecla [enter] é pressionada. Se forem digitados vários caracteres, estes 
ficarão armazenados no buffer de entrada até que a tecla [enter] seja pressionada. 
Então, cada chamada da função getchar() lerá um caracter armazenado no buffer. 
 
 
putchar() 
Biblioteca: stdio.h 
Declaração: int putchar(int c); 
Propósito: Esta função putchar() (put character) imprime um caracter individual c 
na saída padrão (em geral o monitor de vídeo). 
 
 getchar retorna inteiro mas é possível atribuir a uma variável char (o que 
geralmente é feito). 
 putchar é declarada para entrada de inteiro mas geralmente é usada com 
um argumento caracter. 
 
 
3.6.3.2 Funções de Entrada e Saída para caracteres (sem enter) 
getch(), getche() 
 
Alguns compiladores nào comportam estas funções 
 
Declaração: int getch(void); 
 int getche(void); 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
17 
 
Ao ser executada, a função getch() (get character) aguarda que uma tecla (ou com-
binação de teclas) seja pressionada, recebe do teclado o código correspondente e 
retorna este valor. 
 
A função getche() (get character and echoe) tem o mesmo funcionamento porém 
escreve na tela, quando possível, o caracter correspondente. 
 
 
Exemplo 
// Uso das funcoes getchar() e putchar() 
#include <stdio.h> 
char c; 
void main(void) 
{ 
 printf("\nDigite uma frase:\n"); 
 do 
 { 
 c = getchar(); // leitura do 'buffer' 
 if(c >= 97 && c <= 122) // se c e' minúsculo... 
 { 
 c -= 32; // c=c-32 transforma em maiúsculo 
 } 
 putchar(c); // impressao dos caracteres maiúsculos 
 }while (c != '\n'); // ...enquanto nao e' [enter] 
 
} 
 
 
4.0 Comandos de controle de fluxo 
 
4.1 Comandos Condicionais 
Um comando condicional é usado para selecionar um único comando de seus com-
ponentes para a execução. 
 
4.1.1 Comando if- else 
O comando IF especifica que um comando deve ser executado somente se o re-
sultado de uma expressão lógica for verdadeira. Se for falsa, então outro comando 
deve ser executado, ou nenhum comando da sua estrutura deve ser executado. 
 
Formas do comando: 
 
A) if (condição) 
 comando ; 
 
Nesta forma, o comando somente será executado se a condição for TRUE. Caso 
contrário, se a condição for FALSE, nenhuma ação será realizada. 
O comando a ser executado pode ser simples ou composto. 
Um comando será simples quando for apenas uma linha de instrução (seguida de 
ponto e vírgula) e será composto quando houver mais de uma linha de instrução, 
originando um bloco que deverá ser delimitado por chaves 
 
 Ex: if (a = = b ) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
18 
 
 { 
 x = 1.5 ; 
 y = 2.5 ; 
 } 
 
 
B) if (condição) 
 comando 1; (ou bloco) 
 else 
 comando 2; (ou bloco) 
 
Neste caso, se a condição for verdadeira será executado o comando 1 e caso for 
falsa será executado o comando 2. Tanto o comando 1 como o comando 2 po-
dem ser simples ou compostos. 
 
 
 
Exemplos: 
If (a = = b) 
 x = 1.5; 
else 
 x = 2.5 ; 
 
 
if (a == 
b) 
{ x = 
1.5; 
 x := 1.5 ; 
 y = 2.5 ; 
 
else 
{ x = -1.5 ; 
 y = -2.5 ; 
} 
 
 
Exemplo: Faça um programa que leia um número e informe se é igual a 10, maior 
ou menor que 10. 
#include <stdio.h> 
int num; 
void main (void) 
{ printf ("Digite um numero: "); 
 scanf ("%d",&num); 
 if (num==10) 
 { 
 printf ("\n\nVoce acertou!\n"); 
 printf ("O numero e igual a 10.\n"); 
 } 
 else 
 if (num>10) 
 printf ("O numero e maior que 10."); 
 else 
 printf ("O numero e menor que 10."); 
 } 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
19 
 
4.1.2 Comando condicional switch 
O comando switch é próprio para testar uma variável em relação a diversos valo-
res pré-estabelecidos. É básicamente usado na implementação de menus. 
Sua forma geral é: 
 
switch (variável) 
{ 
case constante_1: declaração_1; 
 break; 
case constante_2: declaração_2; 
 break; 
case constante_n: declaração_n; 
 break; 
default declaração_default; 
} 
A estrutura switch não aceitacondições, apenas constantes. O switch testa 
a variável e executa a declaração cujo case corresponda ao valor atual da variável. 
A declaração default é opcional e será executada apenas se a variável, que está 
sendo testada, não for igual a nenhuma das constantes. Não há necessidade de 
chaves envolvendo as instruções de cada case, pois estas instruções não são con-
sideradas um bloco, mas deve haver um conjunto de chaves envolvendo todo o 
corpo de cases, incluindo default. 
O comando break, faz com que o switch seja interrompido assim que uma 
das declarações seja executada. Mas ele não é essencial ao comando switch. Se 
após a execução da declaração não houver um break, o programa continuará exe-
cutando os cases do switch, na ordem seqüencial, até o fim do switch. 
Exemplo: Faça um programa que leia um número e informe se é igual ou diferente 
de 9, 10 e 11 . 
 
#include <stdio.h> 
int num; 
int main (void) 
{ printf ("Digite um numero: "); 
 scanf ("%d",&num); 
 switch (num) 
 { 
 case 9: 
 printf ("\n\nO numero e igual a 9.\n"); 
 break; 
 case 10: 
 printf ("\n\nO numero e igual a 10.\n"); 
 break; 
 case 11: 
 printf ("\n\nO numero e igual a 11.\n"); 
 break; 
 default: 
 printf ("\n\nO numero não e nem 9 nem 10 nem 
11.\n"); 
 } 
} 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
20 
 
4.2 Comandos de Repetição 
 
4.2.1 Comando for 
Forma geral: 
for (inicialização;teste;incremento) 
 comando ou bloco; 
 
Havendo um bloco de comandos, este deverá ser envolvido por chaves. 
 
O comando for é uma instrução de múltiplos usos, não precisando essas três partes 
separadas pelo operador ; (ponto-e-vírgula). O que deve ser sempre lembrado é a 
interpretação da condição de teste. Tal deve ser pensada com a seguinte frase: 
“faça o laço enquanto o teste for verdadeiro”. 
 
Exemplo 1: Faça um programa que imprima os 100 primeiros números naturais, 
exceto o zero 
 
#include <stdio.h> 
int n; 
int main () 
{ 
 for (n=1; n<=100; n++) 
 printf ("%d ",n); 
 return 0; 
} 
 
Exemplo 2: Faça um programa que imprima os primeiros 20 números pares. 
 
#include <stdio.h> 
int main () 
{ 
 int n=2; 
 for (; n<=40; n+=2) 
 printf ("%d ",n); 
} 
 
No exemplo acima, a parte de inicialização foi omitida para exemplificar que não é 
necessária, desde que essa parte seja realizada em alguma outra parte do código. 
Expandindo esse conceito, pode-se realizar um loop infinito com a instrução for da 
seguinte forma: 
 
#include <stdio.h> 
int main () 
{ int n=2; 
 for (;;) 
 { printf ("%d ",n); 
 n=n*2; 
 } 
 return 0; 
} 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
21 
 
O exemplo exposto implementa um laço (loop) infinito. Observe que não há a parte 
de condição de saída da instrução for. Essa condição de saída, nesse caso, deve 
ser colocada dentro do bloco de instrução do loop, por meio de uma instrução con-
dicional if, por exemplo. 
 
 
4.2.2 Comando while 
 
Forma Geral : 
 while (condição) 
 comando ou bloco; 
 
Exemplo: 
Faça um programa que imprima os 100 primeiro números naturais, exceto o 
zero 
#include <stdio.h> 
int n; 
int main() 
{ 
 n= 1; 
 while (n<=100) 
 { printf(“%d”,n); 
 n++; 
 } 
 return 0; 
} 
 
 
 
4.2.3 Comando do - while 
Forma geral: 
do 
{ 
instrução; 
} while (condição); 
Mesmo que a declaração seja apenas um comando é uma boa prática deixar as 
chaves. O ponto-e- vírgula final é obrigatório. 
A estrutura do-while executa a instrução, testa a condição e, se esta for verdadeira, 
volta para a instrução. Este comando, ao contrário do for e do while, garante que a 
instrução será executada pelo menos uma vez. 
 
4.3 Listas de Exercícios dos Comandos Condicionais e de Repetição 
 
 
1- Faça um programa que, dado um par de valores, que representa as coordena-
das de um ponto no plano, determine o quadrante ao qual pertence o ponto, ou 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
22 
 
então se está na origem ou sobre um dos eixos cartesianos. Permitir a repetição 
da leitura e do cálculo até que o usuário deseje encerrar o programa. 
 
2- Uma empresa decidiu dar uma gratificação especial a seus funcionários, base-
ada no número de horas extras e no número de horas que o empregado faltou 
ao trabalho. O valor do prêmio é obtido pela consulta à tabela abaixo, em que 
H é o número de horas extras subtraído do número de horas faltas. 
H( horas) Prêmio (R$) 
[0,10] 50,00 
(10,20] 80,00 
(20,30] 110,00 
(30,40] 180,00 
(40,100] 250,00 
Considere que o prêmio deverá ser acrescentado ao salário bruto do funcionário 
e sobre este total deve ocorrer um desconto de 8.5% relativo a impostos. 
Dados o salário bruto do funcionário, o número de horas que ele faltou e o nú-
mero de horas-extras que fez (considerar horas e minutos do tipo real ex: 8.30), 
imprimir o salário bruto, o prêmio obtido pelo funcionário e seu salário líquido. 
 
3- Faça um programa que lendo idade em anos e sexo de um associado de um 
clube, conceda desconto na mensalidade a ser paga, observando: 
sexo feminino, até 30 anos desconto de 20% 
sexo “ 31 a 40 anos desconto de 30% 
sexo “ acima de 41 anos desconto de35% 
sexo masculino até 25 anos sem desconto 
sexo masculino acima de 25 anos desconto de 25%. 
Forneça idade e mensalidade a pagar. 
O programa deverá ser encerrando quando o usuário digitar ‘F’ respondendo a 
pergunta: Repetir o cálculo (s/n)? 
 
4- Faça um programa que, tendo como dados de entrada o custo de 5 produtos e 
seus códigos, escreva os seus preços finais (com acréscimo de imposto) e suas 
origens, conforme tabela abaixo: 
Código Origem Imposto 
1 Sul 10% 
2 Sudeste 12% 
3 Leste 11% 
 
5- Faça um programa que escreva de quantas maneiras diferentes pode-se obter 
cada um dos diferentes totais de pontos resultantes do lançamento de dois da-
dos. 
 
6- Faça um programa que leia um valor n, inteiro e positivo, repetindo a leitura caso 
o valor esteja fora do estabelecido, calcula e escreve o valor de E, sendo 
 
7- Faça um programa para imprimir na tela os 25 primeiros múltiplos de um número 
dado 
 
!
1
...
!3
1
!2
1
!1
1
1
n
E 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
23 
 
8- Faça um programa que simula o lançamento de um dado por 10 vezes e fornece 
o número de vezes que saiu cada face do dado. Utilize para simular o lança-
mento as funções rand( ) e srand(). 
 
9- Faça um programa para calcular a soma: 
S = 1 -1/2 + ¼ - 1/6 + 1/8 + ... + 1/200 
 
10- Faça um programa que lê uma seqüência indeterminada de dois valores inteiros 
positivos e forneça o máximo divisor comum pelo processo das divisões suces-
sivas dos dois valores. A leitura encerra quando um dos valores (ou os dois) 
for igual a zero. 
Cálculo do M.D.C. pelo processo das divisões sucessivas: 
Nesse processo efetuamos várias divisões até chegar a uma divisão exata. O 
divisor desta divisão é o m.d.c. Acompanhe o cálculo do m.d.c.(48,30). 
Regra prática: 
1º) dividimos o número maior pelo número menor; 
48 / 30 = 1 (com resto 18) 
2º) dividimos o divisor 30, que é divisor da divisão anterior, por 18, que é o resto 
da divisão anterior, e assim sucessivamente;30 / 18 = 1 (com resto 12) 
18 / 12 = 1 (com resto 6) 
12 / 6 = 2 (com resto zero - divisão exata) 
3º) O divisor da divisão exata é 6. Então m.d.c.(48,30) = 6. 
 
 
4.4 Exercícios Resolvidos 
// Exercicio 5 
#include <stdio.h> 
 
int t,d1,d2,m; 
int main() 
{ 
 for(t=2;t<13;t++) 
 { 
 m=0; 
 for(d1=1;d1<7;d1++) 
 for(d2=1;d2<7;d2++) 
 if (d1+d2==t) 
 m++; 
 printf("total %2d = %2d maneiras\n",t,m); 
 } 
 return 0; 
} 
 
 
 
// Exercício 8 
#include <stdio.h> 
#include <stdlib.h> 
 
int r, x, s1,s2,s2,s3,s4,s5,s6; 
 
int main() 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
24 
 
{ 
 s1=s2=s3=s4=s5=s6=0; 
 srand( time(NULL) ); 
 /* a função time() retorna a hora corrente, 
 ou -1 se ocorrer um erro. Se for passado 'time'como argumento 
 a hora corrente é armazenada em 'time'.*/ 
 
/* srand( ) estabelece um ponto de partida para a sequencia 
gerada por rand() e utiliza a hora do sistema como semente. 
*/ 
 for(x=1;x<11;x++) 
 { 
 r=1+rand()%6; 
/* A função rand() retorna um valor inteiro aleatório entre 
0 e 32767, usamos o resto da divisão por seis mais 1 para 
garantir no. entre 1 e 6 */ 
 printf("gerou %d\n",r); 
 switch (r) 
 { 
 case 1: s1++; break; 
 case 2: s2++; break; 
 case 3: s3++; break; 
 case 4: s4++; break; 
 case 5: s5++; break; 
 case 6: s6++; break; 
 } 
 } 
 printf("1 saiu %d vezes\n",s1); 
 printf("2 saiu %d vezes\n",s2); 
 printf("3 saiu %d vezes\n",s3); 
 printf("4 saiu %d vezes\n",s4); 
 printf("5 saiu %d vezes\n",s5); 
 printf("6 saiu %d vezes\n",s6); 
 return 0; 
} 
 
 
 
5.0 Tipo Ponteiro 
 
Um endereço de memória é como se fosse um número inteiro que serve para es-
pecificar um byte específico de memória. Podemos imaginar a memória do compu-
tador como sendo um enorme vetor onde cada elemento é um byte, acessível atra-
vés de um número inteiro que é seu “endereço”. 
 
Uma diferença básica entre um inteiro qualquer e um inteiro que representa um 
endereço está nas operações que podem ser efetuadas com eles. Enquanto intei-
ros comuns podem ser adicionados, multiplicados, etc., os endereços servem ape-
nas para referenciar posições específicas da memória. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
25 
 
Normalmente, usamos variáveis para armazenar dados (caracteres, reais, inteiros, 
etc.). Se um endereço é como se fosse um número inteiro, nada impede que pos-
samos criar também variáveis para armazenar endereços de memória. Estas vari-
áveis especiais são denominadas ponteiros. 
 
“Uma variável do tipo ponteiro serve para armazenar um endereço de memória”. 
 
 
5.1 Declaração de variáveis do tipo ponteiro 
 
Variáveis Estáticas - O seu valor é referido através do nome da variável, ou seja, 
“o nome da variável é considerado uma expressão designatória do seu valor”. 
Sua vida útil é: 
Variáveis globais: durante toda execução do programa. 
Variáveis Locais: durante a execução do subprograma. 
Variáveis Dinâmicas - Uma variável dinâmica pode ser criada ou destruída dina-
micamente em qualquer ponto durante a execução de um programa. 
O valor de uma variável dinâmica não é referido através de seu nome, mas sim 
através de uma ligação ou ponteiro para outra variável em que este valor está 
armazenado. 
 
Ao passo que com uma variável estática estamos interessados no valor da variável, 
com uma variável do tipo ponteiro estamos interessados no valor para o qual ela 
aponta. 
 
Variável Estática : 
 
num 5 
 
Variável Ponteiro: 
 
p 27 
Antes de criarmos uma variável ponteiro, é preciso definir que tipo de ponteiro va-
mos usar. Note que, para acessar uma informação na memória, ter apenas o seu 
Variável Anônima - aquela cujo 
valor não é obtido diretamente 
através do seu nome, mas sim 
através de uma variável do tipo 
ponteiro. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
26 
 
endereço não é suficiente pois é necessário conhecer também o seu tamanho 
(quantos bytes devemos acessar a partir do endereço). 
 
Sintaxe da declaração de um ponteiro: 
 
É preciso definir para que tipo de dado o ponteiro vai apontar: 
 
 tipo * identificador_da variável; 
 
Exemplos: 
 uma variável denominada p e que aponta para inteiro: 
 int *p 
 dois ponteiros para char: 
 char *temp,*pt2 
 
Para armazenar o endereço de uma variável ponteiro o compilador reservará 2 
bytes (dependendo da máquina). 
 
O valor de uma variável ponteiro não é referido através de seu nome, mas sim 
através de uma ligação ou ponteiro para outra variável em que este valor está ar-
mazenado. 
 
 
5.2 Operadores de ponteiros 
 
5. 2.1 Existem dois operadores especiais para ponteiros: 
 
 & operador unário que devolve o endereço do seu operando 
 
* operador unário que devolve o valor da variável localizada no 
endereço apontado (é o complemento de &) 
 
Tanto & como * têm precedência maior que qualquer operador aritmético, ex-
ceto o menos unário. 
 
Exemplos de declaração, atribuição e operadores em ponteiros: 
int *p, c, q, *px, *py; 
 
 
c=100; 
p=&c; 
q=*p; 
 
 
*px=5; 
 
 
*py=*py 
/* as variáveis p, px e py são do tipo pon-
teiro para inteiros, as variáveis c e q são 
do tipo inteiro*/ 
//c recebe 100 
/* p armazena o endereço que a variável c 
ocupa na memória, logo p aponta para c*/ 
/*q armazena o valor que esta armazenado no 
 // ende-
reço para o qual p aponta (100) 
endereço para onde p aponta*/ 
 
/* armazena o valor 5 na variável apontada 
pelo ponteiro px */ 
 
*/armazena na variável apontada por py o 
mesmo valor que está na variável apontada 
por px (5) */ 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
27 
 
 
Observação: Na declaração, o símbolo * indica o “tipo apontado” em outras 
instruções indica “a variável apontada por”. 
 
Um exemplo: 
#include <stdio.h> 
int main () 
{ int a, *pa; 
 double b, *pb; 
 char c, *pc; 
// atribuições de endereços 
 pa = &a; pb = &b; pc = &c; 
// atribuição de valores 
 a = 1; b = 2.34; c = '@'; 
printf("\n valores:%5d %5.2lf %c", a, b, 
c); 
printf("\n ponteiros:%5d %5.2lf %c", *pa, 
*pb, *pc); 
printf("\n enderecos:%p %p %p", pa, pb, 
pc); 
/* mais atribuições de valores usando os pontei-
ros*/ 
 *pa = 77; *pb = 0.33; *pc = '#'; 
 printf("\n valores :%5d %5.2lf %c", a, b, 
c); 
 printf("\n ponteiros:%5d %5.2lf %c", *pa, 
*pb, *pc); 
printf("\n enderecos:%p %p %p\n", pa, pb, 
pc); 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
Ponteiros também são variáveis e, portanto, ocupam posições na memória: 
#include <stdio.h> 
int main() 
{ int a, *pa; 
 double b, *pb; 
 char c, *pc; 
 // atribuições de endereços 
 pa = &a; pb = &b; pc = &c; 
 // mostra o endereço das variáveis 
 printf("\nendereço de a, b e c: %p %p %p", pa, pb, pc); 
 // mostra o endereço das variáveis de outra forma 
 printf("\nendereço de a, b e c (outra forma): %p %p %p", &a, 
&b, &c); 
 // mostra o endereço dos ponteiros 
 printf("\nendereço dos ponteiros: %p %p %p\n", &pa, &pb, 
&pc); 
 return 0; 
} 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
28 
 
 
 
 
5.2.2 Operações com Ponteiros 
 
5.2.2.1 Atribuição entre ponteiros 
 
Se temos dois ponteiros, p1 e p2 podemos fazer 
 p1=p2. 
 
 Repareque estamos fazendo com que p1 aponte para o mesmo lugar 
que p2 aponta. 
 Se quisermos que a variável apontada por p1 tenha o mesmo conteúdo 
da variável apontada por p2 devemos fazer *p1=*p2. 
 
 
 
5.2.2.2 Operações aritméticas com Ponteiros: apenas duas 
 
 Incremento de um ponteiro 
Quando incrementamos um ponteiro ele passa a apontar para o próximo valor do 
mesmo tipo para o qual o ponteiro aponta. Isto é, se temos um ponteiro para um 
inteiro e o incrementamos, ele passa a apontar para o próximo inteiro. 
 
Esta é mais uma razão pela qual o compilador precisa saber o tipo de um pon-
teiro: se você incrementa um ponteiro char* ele anda 1 byte na memória e se você 
incrementa um ponteiro double* ele anda 8 bytes na memória. 
 
Considere ptr um ponteiro para inteiro que contém o valor atual 2000 e 2 bytes o 
tamanho necessário para um inteiro. 
Após a expressão: 
 
 ptr++ 
 
ptr conterá 2002 (e não 2001) 
 
Cada vez que ptr for incrementado, ele apontará para a posição do próximo 
inteiro. 
Em outras palavras, os ponteiros são incrementados relativamente ao tamanho do 
tipo base. 
 
 Decremento de um ponteiro 
O decremento funciona de forma semelhante ao incremento 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
29 
 
Supondo que p, p1 e p2 sejam ponteiros para inteiros: 
 
p++; // p aponta para o próximo inteiro 
p--; // p aponta para o inteiro anterior 
p1=p2+3; // p1 aponta para o terceiro inteiro após o inteiro apontado por p2 
 
 
 
5.2.2.3 Operadores relacionais 
Considerando ponteiros de mesmo tipo, é possível utiliza-los em expressões que 
contenha operadores relacionais: 
 
 podemos saber se dois ponteiros são iguais ou diferentes (== e !=). 
 no caso de operações do tipo >, <, >= e <= estamos comparando qual pon-
teiro aponta para uma posição mais alta na memória. Então uma compara-
ção entre ponteiros pode nos dizer qual dos dois está "mais adiante" na me-
mória. 
 A comparação entre dois ponteiros se escreve como a comparação entre ou-
tras duas variáveis quaisquer: 
 
If (p1<p2) 
 printf(“p1 aponta para uma memória mais baixa que p2\n”); 
 
 
5.2.2.4 Operações não permitidas com ponteiros 
 
Não é possível: 
 dividir ou multiplicar ponteiros, 
 adicionar dois ponteiros, 
 adicionar ou subtrair floats ou doubles de ponteiros. 
 
 
5.3 Ponteiros para Ponteiros 
 
Um ponteiro para ponteiro pode ser imaginado com a situação de anotarmos em 
um papel o local onde está guardado o endereço da casa de um amigo. 
 
Declaração de um ponteiro para um ponteiro: 
tipo_da_variável **nome_da_variável; 
 
onde: 
 **nome_da_variável é o conteúdo final da variável apontada; 
 *nome_da_variável é o conteúdo do ponteiro intermediário. 
 
Um exemplo: 
#include <stdio.h> 
int main() 
{ 
 float fpi = 3.1416, *pf, **ppf; 
 pf = &fpi; /* pf armazena o endereco de fpi */ 
 ppf = &pf; /* ppf armazena o endereco de pf */ 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
30 
 
 /* imprime o valor armazenado no endereço apontado por pf */ 
printf("valor armazenado no endereço apontado por pf: %f\n", 
*pf); 
 /* Imprime o valor armazenado no endereço apontado pelo ponteiro 
(pf) para o qual ppf aponta */ 
 printf("Valor armazenado no endereço apontado por ppf: %f\n", 
**ppf); 
 return 0; 
} 
 
 
5.4 Inicialização de ponteiros – a constante “NULL” 
A biblioteca stdio.h define uma macro especialmente para que façamos a iniciali-
zação de um ponteiro, informando que ele não tem um endereço associado 
 
É muito importante que saibamos para onde o ponteiro está apontando, ou seja: 
nunca use um ponteiro que não foi inicializado. 
O exemplo abaixo ilustra esta situação: 
int main () 
/* Nao Execute!!! */ 
{ int n,*p; 
 n=22; 
 *p=n; 
 Return 0; 
} 
Este programa compilará e rodará. Mas o ponteiro p pode estar apontando para 
qualquer lugar. 
Estamos gravando o número 22 em um lugar desconhecido. 
Com um número apenas, não vamos ver nenhum defeito. Porém se tivermos por 
ábito gravar números em posições aleatórias no computador, o micro poderá tra-
var. 
 
!! Inicialize sempre os seus ponteiros com o valor NULL !! 
 
 
 
5.5 Alocação dinâmica de memória 
 
Considerando a declaração abaixo: 
int *p 
 
identificamos que p é uma variável que aponta para valores inteiros (ou seja, arma-
zena seu endereço). 
 
No início da execução de um bloco em que esta variável é declarada, a variável p 
é criada (tal como acontece com as varáveis estáticas). Depois de sua criação p 
existe, embora não exista ainda a variável do tipo int para onde ela aponta, 
situação que pode ser representa como no esquema abaixo: 
 
 p ? 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
31 
 
Para que p possua um endereço (aponte para um endereço), é preciso que faça-
mos uma alocação dinâmica de memória (um pedido de memória do tamanho cor-
reto para armzenar um valor inteiro). 
 
 
A alocação dinâmica permite ao programador alocar memória para variáveis 
quando o programa está sendo executado. Assim, poderemos definir, por exemplo, 
um vetor ou uma matriz cujo tamanho descobriremos em tempo de execução. A 
memória alocada pelas funções de alocação dinâmica é obtida do heap. 
 
 
 
 
O heap é a região de memória livre que 
se encontra entre o programa (com a 
área de armazenamento permanente) 
e a pilha (stack). 
O tamanho do heap é, a princípio, des-
conhecido do programa. 
 
 
 
Existe uma função especial em C para alocarmos memória no heap, a função 
malloc(). 
 
 
5.5.1 Função malloc 
A função malloc() serve para alocar memória de forma dinâmica. 
Sintaxe: void malloc (int size); 
Biblioteca: stdlib.h 
 
A função recebe o número de bytes que queremos alocar (size), aloca na memó-
ria e retorna um ponteiro void * para o primeiro byte alocado. 
 
O ponteiro void * pode ser atribuído a qualquer tipo de ponteiro por isso, deve ser 
utilizado sempre um typecasting (conversão para o tipo apropriado). 
 
Se a memória for alocada no topo do heap, o heapPointer é atualizado (incremen-
tado de size). 
 
Ex: sendo p um ponteiro para inteiro fazemos o typecasting para inteiro 
p= (int *) malloc( sizeof(int) ); 
 
 como não sabemos necessariamente o comprimento de um inteiro (2 ou 4 
bytes dependendo do compilador), usamos como parâmetro sizeof(int). 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
32 
 
Se não houver memória suficiente para alocar a memória requisitada a função 
malloc() retorna NULL. 
 
 
Após realizar a alocação de um endereço, nosso ponteiro p já possuirá uma variá-
vel anônima a ele associada: 
 
p ? 
 
 
Porém, a variável anônima associada a p não está armazenando ainda nenhum 
valor. Para isso fazemos uma atribuição (ou uma leitura): 
 
*p = 97; 
 
o que pode ser graficamente representado como: 
 
p 97 
 
 
Exemplo e esquema representativo da memória durante a alocação dinâmica de 
memória: 
 
 
#include <stdlib.h> 
int *pi; (1) 
int main () 
{ 
 pi = (int *) malloc (sizeof(int)); (2) 
 *pi=97; (3) 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
(1) (2) (3) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
33 
 
5.5.2 Função free() 
 
 A função free(p) libera a região de memória apontada por p para uso. 
 O tamanho liberado está implícito, isto é, é igual ao que foi alocado anterior-
mente por malloc. 
 Caso p seja um ponteironulo nenhuma ação é executada. 
 
Declaração: void free(void *p); 
Biblioteca: stdlib.h 
 
O trecho de código abaixo aloca dinâmicamente um inteiro e depois o libera: 
 
#include <stdlib.h> 
int main(int) 
{ 
 int *pi; 
 pi = (int *) malloc (sizeof(int)); 
 ... 
 … 
 free(pi); 
} 
 
 
6.0 Modularização (subprogramas) 
 
6.1 Introdução ao conceito de modularização 
 
Exemplos de modularização, i.e., sistemas que são compostos por módulos com 
funções bem definidas e tão independentes quanto possível, são bem conheci-
dos. Um destes exemplos que pode ser citado, são os sistemas (domésticos ou 
não) de som, onde há um módulo responsável pela amplificação, outro para sinto-
nizar rádio, outro para amplificar o som, ler CDs e assim por diante. 
 
A divisão de um sistema em módulos tem várias vantagens. Para o fabricante, a 
modularização tem a vantagem de reduzir a complexidade do problema, dividindo-
o em subproblemas mais simples, que podem inclusive ser resolvidos por equipes 
independentes. Sob o ponto de vista da fabricação, é mais simples alterar a com-
posição de um módulo, por exemplo, porque se desenvolveram melhores circuitos 
para o amplificador, do que alterar a composição de um sistema integrado. Por 
outro lado, é mais fácil detectar problemas e resolvê-los, pois os módulos são, em 
princípio, razoavelmente independentes. Claro que os módulos muitas vezes não 
são totalmente independentes. Por exemplo, o sistema de controle à distância de 
uma aparelhagem implica interação com todos os módulos simultaneamente. 
 
A arte da modularização está em identificar claramente que módulos devem existir 
no sistema, de modo a garantir que as ligações entre os módulos sejam minimiza-
das e que a sua coesão interna seja máxima. Isto significa que, no caso de um 
bom sistema de alta fidelidade, os cabos entre os módulos são simplificados ao 
máximo e que os módulos contenham apenas os circuitos que garantem que o mó-
dulo faça sua função. A coesão tem, portanto, a ver com as ligações internas a 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
34 
 
um módulo, que idealmente devem ser maximizadas. Normalmente, um módulo é 
coeso se tiver uma única função, bem definida. 
 
Para quem utiliza, por outro lado, a modularização tem como vantagem principal 
permitir a alteração de um único módulo sem ter de comprar um sistema 
novo. Claro que para isso acontecer o novo módulo tem de (1) ter a mesma função 
do módulo substituido e (2) possuir uma interface idêntica (os mesmo tipo de cabos 
com o mesmo tipo de sinal eléctrico). Isto é, os módulos, do ponto de vista do 
utilizador, funcionam como "caixas pretas" com uma função bem definida e com 
interfaces bem conhecidas. Para o utilizador o interior de um módulo é irrelevante. 
 
Mas a modularização tem outras vantagens: o amplificador pode no futuro ser reu-
tilizado num sistema de vídeo, por exemplo, evitando a duplicação de circuitos com 
a mesma função. 
 
As vantagens da modularização são muitas e foi introduzida na programação a 
partir das linguagens como o C e o Pascal. É um dos métodos usados em progra-
mação para desenvolvimento de programas de grande escala mas é útil mesmo 
para pequenos programas, quanto mais não seja pelo treino que proporciona. 
Vantagens da modularização para a programação: 
1. Facilita a detecção de erros, pois é em princípio simples verificar qual é o 
módulo responsável pelo erro. 
2. É mais fácil testar os módulos individualmente do que o programa com-
pleto. 
3. É mais fácil fazer a manutenção (correcção de erros, melhoramentos, etc.) 
módulo por módulo do que no programa total. Além disso, a modulariza-
ção aumenta a probabilidade dessa manutenção não ter consequências 
nefastas nos outros módulos do programa. 
4. Permite o desenvolvimento independente dos módulos. Isto simplifica o 
trabalho em equipe, pois cada elemento, ou cada sub-equipe, tem a seu 
cargo apenas alguns módulos do programa. 
5. A mais evidente vantagem da modularização em programas de pequena 
escala, mas também nos de grande escala, é a possibilidade de reutiliza-
ção do código desenvolvido. 
Um programador assume, ao longo do desenvolvimento de um programa, os dois 
papeis descritos acima: por um lado é fabricante, pois é sua responsabilidade de-
senvolver módulos; por outro é utilizador, pois fará com certeza uso de outros mó-
dulos, desenvolvidos por outrem ou por ele próprio no passado. Esta é uma noção 
muito importante. É conveniente que um programador possa ser um mero utilizador 
dos módulos já desenvolvidos, sem se preocupar com o seu funcionamento interno: 
ele sabe qual a interface do módulo e qual a sua função, e usa-o. Isto permite 
reduzir substancialmente a complexidade da informação que o programador tem 
de ter presente na sua memória, conduzindo por isso a substanciais ganhos de 
produtividade e a uma menor taxa de erros. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
35 
 
Em nosso estudo, até agora, já entramos em contato com o uso de módulos pron-
tos. São as funções que utilizamos para limpar a tela, escrever na tela, fazer en-
trada de dados e outras. 
 
Existem basicamente duas formas de criar subprogramas: utilizar procedimentos 
ou funções. A linguagem C só permite a utilização de funções , por isso enfocare-
mos basicamente funções em nossas aulas. 
Um procedimento é um conjunto de instruções, com interface bem definida, que 
pode receber e enviar dados para quem o acionou, normalmente o programa prin-
cipal. 
 
Uma função por sua vez, também segue a definição acima, com a diferença de que 
devem ter obrigatóriamente um tipo definido para o valor que a função retorna. Em 
outras palavras, funções só não retornam um valor se as definirmos como void. 
 
Uma vez definida ("fabricada"), uma função, ou um procedimento, podem ser utili-
zados sem que se precise conhecer o seu funcionamento interno, da mesma forma 
que o usuário da aparelhagem de som não está muito interessado nos circuitos 
dentro do amplificador, mas simplesmente nas suas características. Claro, para que 
funcuione adequadamente, é preciso saber conectar o equipamento ao sistema. O 
mesmo acontece com as funções e os procedimentos. 
Tomemos como exemplo uma função que é utilizada para gerar automáticamente 
números aleatórios, a função rand. Para poder utilizá-la devemos conhecer primeiro 
seu protótipo (cabeçalho da função). O protótipo irá nos mostrar qual o tipo e os 
parâmetros de rand. Onde procurar esta informação? Tenha sempre a mão um bom 
livro de C ou utilize o help do turbo C. O protótipo é: 
 
 
 int rand(void) 
int informa que a função retorna um valor inteiro 
rand é seu nome 
e (void) indica que ela não requer parâmetros. 
 
 
Outro exemplo é a função matemática sqrt. Esta função, como já estudamos, in-
forma como resultado (retorna) a raiz quadrada de um número. Para fazer este 
cálculo devemos colocar entre parênteses (como parâmetro) o valor ou a variável 
que servirá para fazer o cálculo da raiz quadrada e devemos declarar uma variável 
apropiada para armazenar o resultado. Veja na tabela 4. 
 
 
Exemplo: 
#include math.h 
float r,n; 
int main () 
{ r=sqrt(16); // r armazena o retorno da função cujo parâmetro 
é 16*/ 
 ------; 
 ------; 
 return 0; 
} 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
36 
 
 
 
Para usarmos funções prontas, portanto, não necessitamos conhecer o seu código, 
porém é importante conhecer seu protótipo (tipo que retorna, nome da função e 
parâmetros que requer). 
 
 
Mas nem sempre utilizaremos apenas funções prontas, muitas vezes “fabricare-
mos” nós mesmos nossas funções. 
 
6.2 Definiçãode funções em C 
 
 
 
Outra observação: Se não declaramos o tipo de uma função ela será considerada 
int. 
 
 
6.3 Escopo de uma variável (região de validade) tipos de parâmetros e retorno 
de funções 
 
 Variáveis Globais (Estáticas): são declaradas fora das funções e são reco-
nhecidas em todo o programa (em main e inclusive nos demais subprogra-
mas). 
 
 Variáveis Locais: são declaradas no bloco da função e são válidas apenas 
na função. São alocadas através da requisição de espaço na pilha (stack) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
37 
 
e permanecem na memória somente durante a execução da função, deixando 
de existir quando a função é encerrada. 
 
 
 
Exemplo2: Faça um programa que leia três valores reais que representam a base 
maior, base menor e altura de um trapézio, calcule e informe a área do trapézio. 
 
 
#include <stdio.h> 
 
 
int main () 
{ 
 float bmai,bmen,h,area; 
 printf("Digite a base 
maior\n"); 
 printf("Digite a base me-
nor\n"); 
 printf("Digite altura do tra-
pezio\n"); 
 
scanf("%f%f%f",&bmai,&bmen,&h); 
 area=(bmai+bmen)/2*h; 
 printf("area do trapezio: 
5.2f\n",area); 
 return 0; 
} 
 
#include <stdio.h> 
 
void calculo (float ma, float me, 
float altura); 
int main () 
{ 
 float bmai,bmen,h; 
 printf("Digite a base maior\n"); 
 printf("Digite a base menor\n"); 
 printf("Digite altura do trape 
zio\n"); 
 scanf("%f%f%f",&bmai,&bmen,&h); 
 calculo(bmai,bmen,h); 
} 
void calculo (float ma, float me, 
float altura) 
{ 
 float area; 
 area=(ma+me)/2*altura; 
 printf("Area: %5.2f",area); 
} 
Ex2: sem função Ex2: com função e parâmetros, sem retorno 
 
É importante observar que, antes da função main, foi feita a declaração do protótipo 
da função, que consiste em colocar seu cabeçalho seguido de ponto e vírgula. Isto 
é feito para informar ao compilador a existência do código da função após main. 
Para evitar a declaração do protótipo, a função poderia ser implementada antes de 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
38 
 
main, colocando exatamente as mesmas instruções que foram colocadas após 
main, sem o ponto e vírgula ao final da linha do cabeçalho. 
Portanto, sempre que implementarmos o código de funções após main, deveremos 
fazer a declaração de seu protótipo antes de main. Apenas as funções que tiverem 
como retorno o tipo int não precisarão seguir esta regra. 
 
A função calculo foi implementada com 4 variáveis locais: 
bma, bme, alt: são declaradas entre parênteses, pois são parâmetros da função. 
area: declarada no corpo da função porque não é parâmetro 
 
A função calculo não precisa retornar nada para quem a chamou, logo seu tipo é 
void. 
 
Ao ser acionada uma função com parâmetros, devemos informar os valores, entre 
parênteses e estes ficarão armazrnados nas variáveis locais declaradas dentro dos 
parênteses, na mesma ordem em que são colocados. 
No exemplo teremos a variável bma passando seu valor para o parâmetro ma, te-
remos a variável bme passando seu valor para o parâmetro me e a variável h pas-
sando seu valor para o parâmetro altura. 
 
Assim, existirá uma comunicação de informações entre main e a função calculo que 
é a passagem destes valores, lidos em main e sem os quais a função não poderia 
efetuar o calculo. 
 
Esta comunicação se dá somente no sentido de main para função (e não vice-
versa) e é conhecida como passagem de parâmetros por valor. 
Neste exemplo a função nada retorna, visto que ela mesma informa o resultado do 
cálculo, mas poderíamos entender que seria melhor se a função retornasse a área 
calculada para quem a acionou. 
O exemplo abaixo apresenta uma forma de resolução onde a área calculada é o 
retorno da função . 
 
#include <stdio.h> 
float calculo (float ma, float me, float altura); 
int main () 
{ 
 float bmai,bmen,h,a; 
 printf("Digite a base maior\n"); 
 printf("Digite a base menor\n"); 
 printf("Digite altura do trapezio\n"); 
 scanf("%f%f%f",&bmai,&bmen,&h); 
 a=calculo(bmai,bmen,h); 
 printf("Area: %5.2f",area); 
 return 0; 
} 
 
float calculo (float ma, float me, float altura) 
{ float area; 
 area=(ma+me)/2*altura; 
 return(area) 
} 
Ex3: resolução com retorno da função 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
39 
 
Observe autilização do comando return antes de encerrar a função. Através deste 
comando estamos informando qual o retorno desta função, no caso o valor arma-
zenado na variável local área, que por isso deve ser do mesmo tipo da função. 
 
Outra forma de passarmos valores para “fora” de uma função é através dos parâ-
metros. Podemos declarar parâmetros de forma que eles não só recebam um valor 
de quem aciona a função mas ao mesmo tempo retornem um valor para a variável 
que se corresponde com o parâmetro. 
 
 
Esta forma de passagem de parâmetros é chamada de passagem por referência 
e consiste em informarmos o endereço da variável no acionamento da função. Por 
sua vez, o parâmetro correspondente deverá ser declarado como tipo ponteiro, 
para poder armazenar este endereço. 
 
 
Exemplo: Faça um programa que leia 3 valores inteiros (a,b e c) e escreva-os or-
denados, de forma que em a esteja o menor valor e em c o maior. 
 
#include <stdio.h> 
int main () 
{ 
 int a,b,c,aux; 
 printf("Informe os tres inteiros\n"); 
 scanf("%d %d %d",&a,&b,&c); 
 if (a>b) 
 {aux=a; 
 a=b; 
 b=aux; 
 } 
 if (a>c) 
 {aux=a; 
 a=c; 
 c=aux; 
 } 
 if (b>c) 
 {aux=b; 
 b=c; 
 c=aux; 
 } 
 printf("a=%d b=%d c=%d",a,b,c); 
 return 0; 
} 
 
 
Percebe-se que a cada vez que o teste entre as variáveis for verdadeiro será reali-
zado um mesmo bloco de instruções, que troca as variáveis envolvidas no teste. 
Este trecho de código pode ser implementado em uma função que receba os valo-
res e devolva-os trocados, como é mostrado abaixo, realizando uma passagem de 
parâmetros por referência. 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
40 
 
#include <stdio.h> 
void troca(int *x, int *y); 
int main () 
{ 
 int a,b,c; 
 printf("Informe os tres inteiros\n"); 
 scanf("%d %d %d",&a,&b,&c); 
 if (a>b) 
 troca(&a,&b); 
 if (a>c) 
 troca(&a,&c); 
 if (b>c) 
 troca(&b,&c); 
 printf("a=%d b=%d c=%d\n",a,b,c); 
 return 0; 
} 
void troca (int *x, int *y) 
{ 
 int aux; 
 aux=*x; 
 *x=*y; 
 *y=aux; 
} 
 
 
Variáveis Locais Estáticas 
 
É possível, quando da declaração de variáveis prefixá-las com o qualificador static. 
 As variáveis locais estáticas são inicializadas uma só vez e não desapare-
cem quando a função a que pertencem termina, podendo no entanto ser 
acessadas apenas dentro da função. 
 As variáveis locais estáticas também mantêm o seu valor de umas chama-
das para as outras, como se vê nos exemplos seguinte: 
 
Exemplo: 
 
#include <stdio.h> 
void func (int x); 
int main () // função principal 
{ func (10); 
 func (20); 
 func (30); 
 return 0; 
} 
 
void func (int x) 
{ /* declaração de 1variável local, porém estática, 
 e por isso, permanece com o valor da chamada anterior*/ 
 static int s = 0; 
 printf("\n valor de s no inicio da funcao = %5d", s); 
 s = s + x; 
 printf("\n valor de s no final da funcao = %5d", s); 
} 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
41 
 
 6.4Inclusão de arquivos de cabeçalho com funções criadas pelo usuário 
 
Podemos criar um arquivo cabeçalho (*.h) com as funções que acharmos apropri-
adas, geralmente aquelas que são muito utilizadas. Abaixo apresenta-se o mesmo 
exemplo utilizado para demonstrar passagem de parâmetros por referência, visto 
anteriormente. Agora, porém, a função que faz a troca entre os valores está imple-
mentada em um arquivo externo, chamado uteis. h. Veja abaixo: 
 
#include <stdio.h> 
#include"d:\tc\bin\A09_01\ 
Ex_incl\uteis.h" 
 
int main () 
{ 
 int a,b,c,aux; 
 printf("Informe os 
tres inteiros\n"); 
 scanf("%d %d 
%d",&a,&b,&c); 
 if (a>b) 
 troca(&a,&b); 
 if (a>c) 
 troca(&a,&c); 
 if (b>c) 
 troca(&b,&c); 
 printf("a=%d b=%d 
c=%d",a,b,c); 
 return 0; 
} 
//arquivo .h que possui uma funcao 
para trocar dois inteiros 
 
//----------------------------------- 
//cabeçalho da função 
 
void troca(int *x, int *y); 
 
//----------------------------------- 
// desenvolvimento da função 
 
void troca(int *x, int *y) 
{ int aux; 
 aux=*x; 
 *x=*y; 
 *y=aux; 
} 
 
OBS: quando delimitamos o arquivo cabeçalh < > estamos direcionando sua 
busca no diretorio padrao de inclusao (a pasta include do diretorio tc), quando uti-
lizamos " " significa o diretorio corrente, ou podemos especificar um caminho. 
Para criar um arquivo header acione o menu File - New e depois File outra vez. 
Escolha header: 
 
 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
42 
 
6.5 Exercícios propostos 
 
1. Escreva uma função que dadas as notas de prova p1 e p2 e as notas dos exer-
cícios-programa ep1, ep2 e ep3 de um aluno, devolve o valor da média final 
deste aluno. A média final do aluno é dada por (3p+ep)/4, onde p = (p1+2p2)/3 
e ep = (ep1+2ep2+3ep3)/6. 
 
2. Idem, acrescentando se p<5 ou ep<6 a média final é o mínimo entre 4.5, p e 
ep. 
 
3. Fazer um programa que possibilite várias opções de cálculos a partir de um 
menu. O programa chamará a função correspondente a cada cálculo. 
a- S = 1/1 + 3/2 + 5/3+........+ 99/50 
b- S = 1/1 - 2/2 + 3/3 -..........- 10/10 
c- S = 1000/1 - 997/2 + 994/3......... 
d- S = 480/10 - 475/11 + 470/12 - ....... 
e- Sair 
Obs.: Nas opções c e d fazer os cálculos para os 20 primeiros termos. 
O menu deverá ficar disponível até ser escolhida a opção e. 
 
4. Faça uma função que receba como argumento os valores dos lados de um tri-
ângulo, a função deverá retornar 0 se triângulo for equilátero, 1 se for isósce-
les ou 2 se for escaleno. 
 
5. Fazer um programa em C que solicita o total gasto pelo cliente de uma loja, 
imprime as opções de pagamento, solicita a opção desejada e imprime o valor 
total das prestações (se houverem). 
a - Opção a vista com 10% de desconto 
b- Opção em duas vezes (preço da etiqueta) 
c- Opção de 3 até 10 vezes com 3% de juros ao mês (somente para compras 
acima de R$ 100,00). 
OBS: fazer uma função que imprime as opções, solicita a opção desejada e 
retorna a opção escolhida. 
 No programa principal, testar a opção escolhida e ativar a função correspon-
dente (uma função para cada opção). 
 
6. Faça um programa para ler valores inteiros até ser digitado o valor -1 (tarefa 1) 
e fornecer o fatorial de cada valor lido (tarefa2). 
 
7. Faça um programa que verifica quais dentre os 1000 primeiros números natu-
rais são número perfeito. Número perfeito é todo número que, somando seus 
divisores, esta soma resulta nele mesmo. Utilize uma fção para a verificação 
de cada um dos números. A função main deve informar o resultado. 
 Ex: 6 é divisível por 1 6 é divisível por 2 6 é divisível por 3 
 1+2+3 = 6 é quadrado perfeito. 
 
8. Faça um programa que lê os seguintes dados relativos a 30 alunos de uma 
escola de futebol: altura; data de nascimento (tarefa de main). O programa de-
verá fornecer como saída: a idade média dos alunos (tarefa2); a altura média 
dos alunos (tarefa 3). 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
43 
 
9. A prefeitura de uma cidade fez uma pesquisa entre seus habitantes, coletando 
dados sobre o salário e o número de filhos. A prefeitura deseja saber: 
 média do salário da população (utilize 1 função); 
 média do número de filhos ((utilize 1 função); 
 maior salário (utilize 1 função); 
 percentual de pessoas com salário até R$920,00 (utilize 1 função). 
Encerrar a leitura dos dados com salário negativo. 
 
10. Faça um programa onde main imprima na tela os ‘n’ primeiros números primos, 
onde ‘n’ será fornecido pelo usuário. Utilize uma função para verificar se o nú-
mero é primo. 
 
11. Dado n e p inteiros, n,p >= 0, calcular as combinações de n elementos p a p, 
isto é: n! / (p! * (n-p)! ). Utilize funções. 
 
12. A sequência de Fibonacci é a seguinte: 1, 1, 2, 3, 5, 8, 13, 21, ... 
os dois primeiros termos são iguais a 1. Cada termo seguinte é igual `a soma 
dos dois anteriores. Escreva um programa onde main solicita ao usuário o nú-
mero do termo e calcule através de uma função o valor do termo. Main deverá 
escrever o valor do termo. Por exemplo: se o número fornecido pelo usuário for 
igual a 7, main deverá imprimir 13. 
 
13. Escreva um programa em que main solicite ao usuário três números inteiros a, 
b, e c onde a é maior que 1. Uma outra função deve somar todos os inteiros 
entre b e c que sejam divisíveis por a. Main deve informar a soma. 
 
 
6.6 Exercícios Resolvidos 
 
Exercício 1 
#include <stdio.h> 
#include <stdlib.h> 
 
float media(float p1,float p2,float p3,float ep1,float ep2,float ep3); 
 
int main() 
{ float p1,p2,p3,ep1,ep2,ep3; 
 printf("Informe as notas das tres provas:\n"); 
 scanf("%f%f%f",&p1,&p2,&p3); 
 printf("Informe as notas dos tres exercícios:\n"); 
 scanf("%f%f%f",&ep1,&ep2,&ep3); 
 printf("A media eh: %.2f",media(p1,p2,p3,ep1,ep2,ep3)); 
 return 0; 
} 
 
float media(float p1,float p2,float p3,float ep1,float ep2,float ep3) 
{ float p,ep,m; 
 p=(p1+2*p2)/3; 
 ep=(ep1+2*ep2+3*ep3)/6; 
 m=(3*p+ep)/4; 
 return(m); 
} 
 
Exercício 4 
#include <stdio.h> 
#include <stdlib.h> 
int triangulo (float a, float b, float c); 
int main() 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
44 
 
{ float a,b,c; 
 int tipo; 
 printf("Informe os lados do triangulo\n"); 
 scanf("%f%f%f",&a,&b,&c); 
 tipo=triangulo(a,b,c); 
 switch(tipo) 
 { case 0: printf("\n Equilatero"); 
 break; 
 case 1: printf("\n Isosceles"); 
 break; 
 case 2: printf("\n Escaleno"); 
 break; 
 case 3: printf("\n Não formam um triangulo"); 
 break; 
 
 } 
 return 0; 
} 
int triangulo (float a, float b, float c) 
{ int r; 
 if(a<=b+c && b<=a+c && c<= a+b) // teste para saber se podem formar 
triangulo 
 if(a==b && b==c) 
 r=0; 
 else 
 if(a!=b && b!=c && a!=c) 
 r=2; 
 else 
 r=1; 
 else 
 r=3; 
 return (r); 
} 
 
Exercício 8 
#include <stdio.h> 
#include <time.h> 
 
int idade(int day, int month, int year,int d,int m,int a); 
float acum_altura(float a); 
int acum_idade(int i); 
 
 
int main() 
{ const max= 3; 
 char nome[15]; 
 int x,dia,mes,ano,d,m,a,i; 
 float alt,sh,si; 
 struct tm *local; 
 time_t t; 
 t= time(NULL); 
 local = localtime(&t);ano = 1900 + local->tm_year; 
 mes = 1 + local->tm_mon; 
 dia = local->tm_mday; 
 printf("%d\\%d\\%d\n", dia,mes, ano ); 
 for (x=1; x<=max; x++) 
 { printf("Digite nome, altura e data de nascimento\n"); 
 scanf("%s",nome); 
 scanf("%f%d%d%d",&alt,&d,&m,&a); 
 i=idade(dia,mes,ano,d,m,a); 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
45 
 
 si=acum_idade(i); 
 sh=acum_altura(alt); 
 printf("\nidade=%d,idade_acumulada=%0.2f,altura_acumulada= 
%0.2f\n",i,si,sh); 
 } 
 printf("\nIdade media: %0.2f",si/(x-1)); 
 printf("\nAltura media: %0.2f",sh/(x-1)); 
 return 0; 
} 
 
int idade(int day, int month, int year,int d,int m,int a) 
{ int i; 
 if (year>a) 
 { if (month>m) 
 i=year-a; 
 else 
 if (month==m) 
 { if (day>=d) 
 i=year-a; 
 else 
 i=year-a-1; 
 } 
 else 
 i=year-a-1; 
 } 
 else 
 i=0; 
 return (i); 
} 
int acum_idade(int i) 
{ 
 static int si=0; 
 si+=i; 
 return si; 
} 
float acum_altura(float a) 
{ 
 static float sa=0; 
 sa+=a; 
 return(sa); 
} 
 
Exercício 9 
#include <stdio.h> 
#define MIN 420.00 
float acum_real(float sal); 
int acum_inteiro(int n); 
float maior_real(float sal, float maior); 
int conta_se(float sal, float valor); 
int main() 
{ float s, ms, maior=0; 
 int nf,c1=0,c2=0 ,mf; 
 printf("Informe o salario:\n"); 
 scanf("%f",&s); 
 while (s>=0) 
 { printf("Informe o no. de filhos\n"); 
 scanf("%i",&nf); 
 c1++; 
 ms=acum_real(s); 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
46 
 
 mf=acum_inteiro(nf); 
 maior=maior_real(s,maior); 
 c2=conta_se(s,MIN); 
 printf("Informe o salario:\n"); 
 scanf("%f",&s); 
 } 
 printf("media salarial: %5.2f\n",ms/c1); 
 printf("media de filhos: %5.2f\n",(float)mf/c1); 
 printf("maior salario: %5.2f\n",maior); 
 printf("percent. de pessoas com salario ate %5.5f: \n",MIN, 
c2*100/(float)c1); 
 return 0; 
} 
float acum_real(float sal) 
{ static float ar=0; 
 ar=ar+sal; 
 return(ar); 
} 
int acum_inteiro(int n) 
{ static int ai=0; 
 ai=ai+n; 
 return (ai); 
} 
float maior_real(float sal, float maior) 
{ if(sal>maior) 
 maior=sal; 
 return(maior); 
} 
int conta_se(float sal, float valor) 
{ static int c=0; 
 if(sal<=valor) 
 c++; 
 return(c); 
} 
 
 
Exercício 13 
#include <stdio.h> 
 
int soma(int a, int b, int c); 
 
//-----------principal------------------------------------ 
int main(void) 
{ 
 int a,b,c; 
 printf("Informe 3 valores inteiros positivos, a,b e c\n"); 
 printf("Digite a>1 e b<c \n"); 
 scanf("%d%d%d",&a,&b,&c); 
 if ((a>1) && (c>b)) 
 printf("a soma dos multiplos de %d entre %d e %d eh: 
%d",a,b,c,soma(a,b,c)); 
 else 
 printf("fora do solicitado"); 
 return 0; 
} 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
47 
 
//------------calcula soma dos multiplos--------------------- 
int soma(int a, int b, int c) 
{ 
 int x,s=0; 
 for (x=b; x<=c; x++) 
 if (x%a==0) 
 s+=x; 
 return s; 
} 
 
 
 
7.0 Tipo estruturado homogêneo - matrizes 
 
Consiste em uma seqüência ordenada e estruturada de itens de dados (componen-
tes), organizados em dimensões e identificados através de índices (subscritos). Ou 
seja, um array é uma estrutura com um número fixo de componentes, todos do 
mesmo tipo, representados por um único identificador de variável. 
Devido às suas características, muitos autores o denominam tipo estruturado ho-
mogêneo. 
 
Cada elemento de um array é distinguido pelo índice que referencia sua po-
sição dentro da estrutura. 
 
 
7.1.- Matriz Unidimensional : estrutura do tipo lista, vetor, que é referenciado 
por uma variável com um único índice. 
 
 
 
Forma Geral da declaração: 
 tipo_da_variável nome_da_variável [tamanho]; 
 
 Ex: 
 float valores[8]; 
 
Esta declaração cria um espaço na memória para armazenar sequencialmente 8 
valores do tipo float 
O primeiro destes valores estará na posição de índice zero e o último na posição 
7. 
 
 
 
Valores[3] = 13 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
48 
 
7.2 Matriz bidimensional - estrutura do tipo matriz, tabela, que é referencia atra-
vés de dois índices, o primeiro para indicar a linha e o segundo para indicar a co-
luna onde o elemento se encontra. 
 
Forma Geral da declaração: 
 tipo_da_variável nome_da_variável [no. Linhas][no. colunas]; 
 
Exemplo: 
 int tabela [5] [6]; 
 
Esta declaração cria um espaço na memória para armazenar sequencialmente 30 
valores do tipo float 
O primeiro destes valores estará na posição [0][0] ou seja, na linha zero e coluna 
zero e o último estará na posição [4][5]. 
 
 
 
 
 
Tabela[2][3]=85 
 
 
 
 
7.3 Inicialização de matrizes 
Ao declarar uma variável simples é possível definir um valor inicial para a mesma, 
como abaixo: 
int k = 21; 
 
Matrizes também podem ser inicializadas e nesse caso, a sequência de valores 
aparece entre '{' e '}', separados por vírgula. 
 
 
Exemplo de inicialização de matriz unidimensional: 
int dias[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; 
 
Exemplo e inicialização de matriz bidimensional: 
float valores[2][3] = { {1.6, 4.0, 5.1}, {12.9, 6.1, 3.5} }; 
 
 
7.4 O uso de constantes para definir o tamanho de matrizes 
O uso de constantes para definir o tamanho de matrizes é uma boa opção que fa-
cilita a alteração de tamanho o e o teste de programas com matrizes muito gran-
des. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
49 
 
#include <stdio.h> 
#include <conio.h> 
#define TAM_MATRIZ 5 
 
void main(void) 
 { 
 int valores[TAM_MATRIZ], i; 
 
 for (i = 0; i < TAM_MATRIZ; i++) 
 sacnff(" %d", &valores[i]); 
 } 
 
 
7.5 Matrizes como argumento de funções 
 
Ao passarmos uma matriz para uma função, não podemos passar todos os seus 
elementos, podemos passar apenas o endereçco de seu primeiro elemento. Isto 
significa que não é feita uma cópia, elemento a elemento da matriz, mas que a 
função usa o endereço para acessar a matriz real usada na chamada da função. 
Isto faz com que qualquer alteração no valor dos elementos da matriz dentro da 
função, seja efetuada na própria matriz, ou seja, será sempre uma passagem por 
referência. 
 
É possível gerar um ponteiro para uma matriz e isto é feito utilizando apenas o 
nome da matriz, sem índices. 
 
Considerando a declaração de matriz: 
 
int mat[10] que se refere a uma matiz com 10 elementos do tipo inteiro 
 e a declaração de um ponteiro para inteiro: 
 
int *p 
 
podemos fazer a atribuição 
 
p=mat; 
 
e com isso armazenamos o endereço do primeiro elemento de mat em p. 
 
Logo, o nome de uma matriz contém o endereço de seu primeiro elemento. 
 
Um exemplo: 
int v[100]; 
*v = 33; // é o mesmo que v[0] = 33; 
*(v+2) = 44; // é o mesmo que v[2] = 44; 
for (i=0; i<100; i++) 
 *(v+i) = 0; //zera o vetor v 
 
Outro exemplo: 
int v[100]; 
int *pv; 
pv = v; // também pode ser pv = &v[0]; 
Notas de aulade Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
50 
 
for (i = 0; i < 100; i++) 
 *pv[i] = 0; 
 
 
7.5.1 Passagem de matrizes unidimensionais como parâmetro 
Consideremos o vetor 
 int vet [10]; 
que deve ser passado como argumento a uma função func(). 
 
Na chamada da função utilizamos apenas o nome da função e o vetor como argu-
mento: 
 func(vet); 
A função func() poderá ser declarada através de uma das três maneiras seguintes: 
1. void func (int *p); // um ponteiro 
2. void func (int v[10]); // matriz dimensionada 
3. void func (int v[ ]); // matriz não dimensionada 
 
Nos três casos, teremos dentro de func() um ponteiro para o endereço do vetor. 
A primeira declaração usa mesmo um ponteiro 
A segunda usa a declaração padrão de uma matriz 
E a última não especifica o tamanho da matriz 
Pode-se concluir, portanto, que não importa para a função o tamanho do vetor 
pois o compilador gera um código que instrui func() a receber um ponteiro, ele 
não cria realmente uma matriz com 10 elementos inteiros. 
 
Exemplo: 
#include <stdio.h> 
void exibe_matriz(int valores[], int num_de_elementos) 
{ 
 int i; 
 printf("Prestes a exibir %d valores\n",num_de_elementos); 
 for (i = 0; i < num_de_elementos; i++) 
 printf("%d\n", valores[i]); 
} 
 
int main() 
 { 
 int notas[5] = {70, 80, 90, 100, 90}; 
 int conta[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
 int pequeno[2] = {-33, -44}; 
 exibe_matriz(notas, 5); 
 exibe_matriz(conta, 10); 
 exibe_matriz(pequeno, 2); 
 } 
 
7.5.2 Passagem de matrizes bidimensionais como parâmetro 
 
Vimos que ao passar como parâmetro uma matriz unidimensional para uma função, 
não é necessário especificar o número de elementos na matriz. 
Em matrizes bidimensionais, por sua vez, não será necessário especificar o número 
de linhas na matriz, mas, sim, especificar o número de colunas. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
51 
 
Matrizes bidimensionai são armazenadas como um vetor, onde as linhas (come-
çando na linha zero) são armazenadas uma seguida à outra (formando um vetor). 
Assim, para acessar qualquer elemento a partir do primeiro é o compilador executa 
um calculo onde é necessário saber o número de colunas (ou comprimento de cada 
linha). 
 
Exemplo: 
include <stdio.h> 
void exibe_2d_matriz(int matriz[ ][10], int linhas) 
{ 
 int i, j; 
 for (i = 0; i < linhas; i++) 
 for (j = 0; j < 10; j++) 
 printf("matriz[%d][%d] = %d\n", i, j, matriz[i][j]); 
 } 
int main() 
{ 
 int a[1][10] = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; 
 int b[2][10] = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 
 {11, 12, 13, 14, 15, 16, 17, 18, 19,20}}; 
 int c[3][10] = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 
 {11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 
 {21, 22, 23, 24, 25, 26, 27, 28, 29, 30}}; 
 exibe_2d_matriz(a, 1); 
 exibe_2d_matriz(b, 2); 
 exibe_2d_matriz(c, 3); 
 } 
 
7.5.3 Tratando uma matriz bidimensional como se tivesse uma só dimensão 
Quando for necessário trabalhar com os elementos de uma matriz bidimensional, 
mas sem precisar acessar os elementos em suas posições de linha ou coluna, as 
funções poderão tratar a matriz bidimensional como se ela tivesse uma dimensão. 
Exemplo: 
 
#include <stdio.h> 
int soma_matriz(int matriz[], int elementos) 
 { 
 Int soma = 0; 
 int i; 
 for (i = 0; i < elementos; i++) 
 soma += matriz[i]; 
 return(soma); 
 } 
int main() 
 { 
 int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
 int b[2][10]={{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 
 {11, 12, 13, 14, 15, 16, 17, 18, 19,20}}; 
 printf("Soma dos elementos da primeira matriz %d\n", 
 soma_matriz(a, 10)); 
 printf("Soma dos elementos da segunda matriz %d\n", 
 soma_matriz(b, 20)); 
 return 0; 
 } 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
52 
 
7.5.4 Exercícios sobre matrizes 
 
1.0 Escrever um programa em que uma função determine o maior valor em uma 
matriz de valores inteiros com n>0 linhas e m>0 colunas, cujos valores te-
nham sido lidos em main. Main escreve o resultado. 
 
2.0 Alterar o programa anterior utilizando uma função para ler a matriz e outra 
função para indicar todas as posições da matriz em que se encontra tal valor 
máximo. 
 
3. 0 Escrever uma função que determine se uma matriz quadrada de n>0 linhas e 
colunas é uma matriz permutação. Uma matriz quadrada é chamada de ma-
triz permutação se seus elementos são apenas 0’s e 1’s e se em cada linha 
e coluna da matriz existe apenas um único valor. Main lê a matriz e informa 
o resultado. 
 
 
 Exemplo de matriz permutação: 
 
 
4.0 Escrever uma função (e um programa que exercite tal função) que altere os 
valores dos elementos da matriz de valores reais com n>0 linhas e m>0 co-
lunas de tal forma que o valor alterado de um elemento corresponda ao valor 
original daquele elemento dividido pelo maior valor original na coluna em que 
se encontra o elemento em questão. 
 
5.0 Faça um programa que lê uma lista de 5 números inteiros, não aceitando 
valores repetidos. Faça a verificação de repetição através de uma função. 
Main escreve os valores lidos. 
 
 
6.0 Escrever uma função (e um programa que exercite tal função) que deter-
mine o índice da coluna de uma matriz de inteiros (composta por n>0 linhas 
e m>0 colunas) com o maior valor de soma de elementos por coluna. 
 
No exemplo acima a função deve retornar o valor 2, pois a soma dos ele-
mentos da terceira coluna (20) é maior que os valores da soma dos elemen-
tos de cada uma das demais colunas (3, 13 e 18 nas colunas 0, 1 e 3, res-
pectivamente). 
 
7.0 Faça um algoritmo que calcule a multiplicação de duas matrizes A e B, 
sendo inicialmente lidos os valores que correspondem ao número de linhas e 
colunas destas matrizes. Deverá então ser feito o teste para verificar se 
pode ocorrer multiplicação entre A e B e caso seja possível, o algoritmo de-
verá ler as duas matrizes e informar a sua multiplicação. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
53 
 
8.0 Faça um programa no qual: 
Uma função lê os valores de uma lista com nove elementos cujos valores 
devem ser maiores que 1 e menores que 10, chama outra função para o 
qual passa os valores lidos e este identifica os que são ímpares, formando 
com eles uma nova lista, cujos elementos são escritos na tela. 
 A função que leu os valores chama uma terceira função passando para ele 
os 9 valores da lista e esta terceira transforma a lista em uma matriz qua-
drada, a qual escreve na tela. Utilize passagem de parâmetros. 
 
 
 
7.5.5 Exercícios resolvidos 
 
 
Exercício 2 
#include <stdio.h> 
 
#define lmax 10 
#define cmax 10 
 
int fmaior(int mat[][cmax],int l, int c); 
void posicoes(int mat[][cmax],int l, int c, int maior); 
void le_mat_int(int mat[][cmax], int l, int c); 
//-----------principal------------------------------------ 
 
int main() 
{ 
 int mat[lmax][cmax],x,y,l,c,maior; 
 printf("Informe o no. de linhas e depois de colunas\n"); 
 scanf("%i%i",&l,&c); 
 printf("Digite os valores da matriz"); 
 le_mat_int(mat,l,c); 
 maior=fmaior(mat,l,c); 
 printf("O maior valor eh %i\n",maior); 
 posicoes(mat,l,c,maior); 
 return 0;} 
void le_mat_int(int mat[][cmax], int l, int c) 
{int x,y; 
 for (x=0;x<l;x++) 
 for (y=0;y<c;y++) 
 scanf("%i",&mat[x][y]); 
} 
 
int fmaior (int mat[][cmax], int l, int c) 
{ 
 int x,y,ma; 
 ma=mat[0][0]; 
 for (x=0;x<l;x++) 
 for (y=0;y<c;y++) 
 if (mat[x][y]>ma) 
 ma=mat[x][y]; 
 return ma; 
} 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
54 
 
 
void posicoes(int mat[][cmax],int l, int c, int maior) 
{ 
 int x,y; 
 for (x=0;x<l;x++) 
 for (y=0; y<c; y++) 
 if (mat[x][y] == maior) 
 printf("maior encontrado na linha %i coluna %i\n",x,y); 
} 
 
 
Exercício 7 
 
 
 
 
#include <stdio.h> 
#define lmax 5 
#define cmax 5 
 
int teste(int ca,int lb); 
 
void leitura(int ma[][cmax], int mb[][cmax],int la,int ca,int 
lb,int cb); 
 
void multip(int ma[lmax][cmax], int mb[lmax][cmax],int la,int 
ca,int lb,int cb); 
 
int main() 
{ int la,ca,lb,cb,t=0; 
 int ma[lmax][cmax], mb[lmax][cmax]; 
 printf("Informe Linhas e Colunas da matriz A\n"); 
 scanf("%d %d",&la,&ca); 
 printf("Informe Linhas e Colunas da matriz B\n"); 
 scanf("%d %d",&lb,&cb); 
 t=teste(ca,lb); 
 if(t) 
 { leitura(ma,mb,la,ca,lb,cb); 
 multip(ma,mb,la,ca,lb,cb); 
 MULTIPLICAÇÃO DE MATRIZES 
 Dadas as matrizes A (m x n) e B (n x p), chama-se produto de A por B a 
matriz C=A.B, de ordem mxp, tal que cada elemento c
ij
 de C é obtido multi-
plicando-se, ordenadamente, os elementos da linha i de A pelos elemen-
tos da coluna j de B, e somando-se os produtos assim obtidos. 
Para que duas matrizes possam ser multiplicadas é necessário que o número 
de colunas da primeira seja igual ao número de linhas da segunda 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
55 
 
 } 
 else 
 printf("Impossivel multiplicar"); 
} 
int teste(int ca,int lb) 
{ int r=0; 
 if(ca==lb) 
 r=1; 
 return r; 
} 
void leitura(int ma[][cmax], int mb[][cmax],int la,int ca,int 
lb,int cb) 
{ int x,y; 
 printf("Matriz A:\n"); 
 for(x=0;x<la;x++) 
 for(y=0;y<ca;y++) 
 scanf("%d",&ma[x][y]); 
 printf("Matriz B:\n"); 
 for(x=0;x<lb;x++) 
 for(y=0;y<cb;y++) 
 scanf("%d",&mb[x][y]); 
 for (x=0;x<la;x++) 
 for(y=0;y<ca;y++) 
 printf("%d",ma[x][y]); 
 
 for (x=0;x<lb;x++) 
 for(y=0;y<cb;y++) 
 printf("%d",mb[x][y]); 
 
 } 
void multip(int ma[lmax][cmax], int mb[lmax][cmax],int la,int 
ca,int lb,int cb) 
{ int x,y,z,s,mc[lmax][cmax],t; 
 for(x=0;x<la;x++) 
 for(y=0;y<cb;y++) 
 { s=0; 
 for(z=0;z<ca;z++) 
 s=s+ ma[x][z] * mb[z][y]; 
 mc[x][y]= s; 
 } 
 printf("Matriz resultante da multiplicacao"); 
 for (x=0;x<la;x++) 
 for(y=0;y<cb;y++) 
 printf("%d",mc[x][y]); 
} 
 
 
 
 
Exercício 8 
#include <stdio.h> 
 
#define max 9 
void impares(int v, int x); 
void leitura(int l[]); 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
56 
 
void matriz(int l[]); 
int main () 
{ int l[max]; 
 leitura(l); 
 return 0; 
} 
void leitura(int l[]) 
{int x,v,i[max],xi=0; 
 for(x=0;x<max;x++) 
 { printf("Informe o valor (maior que 1 e menor que 10):"); 
 scanf("%d",&v); 
 while(v<=1 || v>=10) 
 { printf("fora do limite, Informe novamente o valor:"); 
 scanf("%d",&v); 
 } 
 l[x]=v; 
 impares(v,x); 
 } 
 matriz(v); 
} 
void impares(int v, int x) 
{ static int i[max]={0,0,0,0,0,0,0,0,0}; 
 int y; 
 static int xi=-1; 
 if (v%2!=0) 
 { xi++; 
 i[xi]=v; } 
 if (x==max-1) 
 {printf("foram lidos %d pares\n",xi+1); 
 if(xi>0) 
 for(y=0;y<xi+1;y++) 
 printf("%d ",i[y]); 
 }} 
 
void matriz(int l[]) 
{ int m[3][3],x,y,z=-1; 
 for(x=0;x<3;x++) 
 for(y=0;y<3;y++) 
 { z++; 
 m[x][y]=l[z]; } 
 printf("matriz quadrada:"); 
 for (x=0;x<3;x++) 
 for (y=0;y<3;y++) 
 printf("%i",m[x][y]); 
 
 
} 
 
 
8.0 Strings em C 
Em C, uma string consiste em um vetor de caracteres finalizado por um zero. Um 
zero é representado como ' \0 ' ou NULL e pode armazenar qualquer tipo de 
caractere válido da tabela ASCII. 
 
8.1 Declaração de strings 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
57 
 
Nâo é necessário que nós mesmos coloquemos o zero ao informar uma string, pois 
o compilador faz isso mas ao declararmos uma string é importante lembrar de dei-
xar um caractere a mais para o valor zero. 
Desta forma, se precisamos de uma string para guardar nomes com 20 caracteres 
a declaração será: 
char nome[21]; 
 
É possível declarar uma string e inicializá-la sem informar o número de caracte-
res, veja abaixo: 
 
 
char string[] = “alo”; 
 
 
O compilador C interpretará que o tamanho da string é a quantidade de caracteres 
da inicialização (3) mais um (1) para o zero, totalizando neste caso, quatro 
elementos. Isto porém será um problema se quisermos (mais tarde) acrescentar 
mais caracteres na variável string, pois não foi reservado espaço préviamente para 
estes novos caracteres. 
 
 
8.2 Declaração de um vetor de string 
 
Para criar um vetor de strings, deve-se utilizar uma matriz bidimensional de 
caracteres, onde o tamanho do índice esquerdo determina o número de strings 
(elementos) do vetor e o tamanho do índice direito especifica o comprimento 
máximo de cada string. 
 
Exemplo: 
 
char nome[3][8]; 
 
 
 
A declaração acima cria um vetor com 3 strings com 7 caracteres + '\0' (NULL) 
cada uma. 
Para acessar uma string particular deve-se especificar apenas o índice esquerdo, 
ou seja, nome[0], nome[1] ou nome[2]. 
 
Pode-se acessar também qualquer caractere de qualquer uma das strings, isto é 
feito utilizando os dois índices, como por exemplo, nome[2][0] é o caracter ‘F’. 
 
 
8.3 Algumas funções para manipular strings 
 
 
9.3.1 Função scanf na leitura de strings 
A função scanf permite a leitura de strings através do formato %s, porém tem um 
funcionamento limitado, pois considera encerrada a leitura da string assim que en-
contrar um espaço em branco. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
58 
 
 
Se, por exemplo, o nome for composto por duas ou mais partes (Ana Maria da 
Silva) a função scanf irá considerar apenas a seqüência de caracteres “Ana” e co-
locará automaticamente o caracter \0 (NULL) para encerrar a string. 
 
 
8.3.1.1 Outros problemas no uso do scanf com caracteres: 
Quando você utiliza, em um mesmo programa C a função scanf, junto com as 
funções gets ou getch, encontra alguns problemas com a aparente "não execu-
ção" de uma ou mais das chamadas destas funções. 
Para o caso do ambientes DOS, usando o BorlandC, basta acrescentar, após o 
uso da scanf, uma chamada à função fflush, na seguinte maneira: 
int main() 
{ char ch; 
 int a; 
.......... 
......... 
........ 
......... 
 scanf(“%i “, &a); 
 fflush(stdin); 
 scanf(“ %c”, ch) 
 
....... 
......... 
........ 
} 
Outra solução é não utilizar o scanf nas leituras, lendo variáveis do tipo integer ou 
real em uma variável auxiliar. Esta variável auxiliar será um vetor de char e será 
lida com gets. Depois será feita a conversão para o tipo adequado e armazenado 
na variável original. Veja abaixo: 
 
int main () 
{ char aux[20]; 
 float r; 
 int i; 
 gets(aux); 
 r=atof(aux); 
 gets(aux); 
 i=atoi(aux); 
} 
 
Quando utilizamos o scanf para ler caracteresdentro de uma repetição, podemos 
ter o mesmo problema, pois, também neste caso, o scanf requer a tecla enter 
para efetuar a entrada de dados e esta tecla, que fica no buffer sinaliza que já 
existe um valor para a variável caractere a ser lida. O compilador C guarda então 
este valor na variável e limpa o buffer. Veja abaixo um exemplo deste problema e 
as duas soluções indicadas. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
59 
 
 
#include <stdio.h> 
// falha na leitura repetida do caracter ch. 
int main() 
{ 
 int i; 
 char ch; 
 
 for (i=0; i<5; i++) 
 { 
 printf(" %i Caractere: ",i+1); 
 scanf("%c", &ch); 
 } 
} 
 
 
Uma solução: 
#include <stdio.h> 
int main() 
{ int i; 
 char ch; 
 
 for (i=0; i<5; i++) 
 { 
 printf("%i Caractere: ",i+1); 
 scanf("%c%*c", &ch); 
 fflush(stdin); 
 } 
 return 0; 
} 
 
Outra solução: 
#include <stdio.h> 
int main() 
{ 
 int i; 
 char ch; 
 
 for (i=0; i<5; i++) 
 { 
 printf("%i Caractere: ", i+1); 
 scanf("%c%*c", &ch); 
 } 
 return 0; 
} 
 
O formato %*c indica que o segundo caractere lido (o enter) deve ser excluído. 
 
8.3.2 Função gets() - pertence à biblioteca stdio.h 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
60 
 
Permite ler uma string através do teclado. Considera encerrada a entrada da 
string quando for digitado o caractere de nova linha (\n) que é representado pela 
tecla <enter>. 
 
8.3.3 Função puts() - pertence à biblioteca stdio.h 
A função puts() é o complemento da função gets() e tem a finalidade de imprimir 
uma string por vez, levando o cursor para próxima linha após imprimir. 
 
Se for necessário imprimir mais de uma string por vez, deve-se usar a função 
printf. 
 
Considerando a declaração: 
char nome[]=“Maria do Carmo”; 
As duas instruções abaixo resultam iguais: 
printf(“%s\n”,nome); 
puts(nome); 
 
8.3.4 Função strlen() – pertence à bibioteca string.h 
Esta função retorna o número de caracteres de uma string passada como parâ-
metro 
Exemplo: 
int c; 
char nome[]=“Maria do Carmo”; 
c=strlen(nome); 
c armazenará 14 
 
8.3.5 Função strcat() - pertence à bibioteca string.h 
Esta função une duas funções juntando uma string ao final da outra. 
Exemplo: 
char nome1[] = “Santa ”, nome2[] = “Cruz”; 
strcat (nome1, nome2); 
puts(nome1) 
Será apresentado Santa Cruz 
 
8.3.6 Função strcmp() - pertence à bibioteca string.h 
Esta função compara duas strings, caracter a caracter e retorna zero se elas fo-
rem iguais. 
Exemplo: 
 
char nome1[] = “Santa ”, nome2[] = “Cruz”; 
int r; 
r=strcmp(nome1, nome2); 
if (r == 0) 
 printf(“São iguais”) 
else 
 printf(“São diferentes”); 
 
No trecho de código do exemplo acima a saída será: São diferentes 
 
8.3.7 Funções para conversão de uma string em valor numérico 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
61 
 
8.3.7.1 Função atof() 
 
Sintaxe: double atof(const char *str) 
Biblioteca: stdlib.h 
Converte a string apontada por str em um valor double e retorna o resultado. 
 
8.3.7.2 Função atoi() 
 
Sintaxe: int atoi(const char *str) 
Biblioteca: stdlib.h 
Converte a string apontada por str em um valor inteiro e retorna o resultado. 
 
 
Programa exemplo que demonstra algumas funções para string e outras 
para caracteres: 
/* Faça um programa que lendo idade em anos e sexo de um associado de um 
clube, conceda desconto na mensalidade a ser paga, observando: 
sexo feminino, até 30 anos desconto de 20% 
sexo “ 31 a 40 anos desconto de 30% 
sexo “ acima de 41 anos desconto de35% 
sexo masculino até 25 anos sem desconto 
sexo masculino acima de 25 anos desconto de 25%. 
Forneça idade e mensalidade a pagar. 
 
O programa deverá ser encerrando quando o usuário digitar ‘Fim’ no lugar do 
nome. */ 
 
#include <stdio.h> 
#include <ctype.h> 
#include <string.h> 
const 
 m=60; 
char nome[15],sexo; 
int idade,t,x,r; 
float mens; 
//-----------principal------------------------------------ 
int main() 
{ 
 printf("Informe nome, para encerrar digite fim:\n"); 
 gets(nome); 
 t=strlen(nome); 
 for(x=0;x<t;x++) //cada caractere é transformado em maiusculo 
 nome[x]=toupper(nome[x]); 
 r=strcmp(nome,"FIM"); //strcmp compara duas strings 
 while(r != 0) 
 { printf("informe idade e sexo\n"); 
 scanf("%i",&idade); 
//scanf("%c",&sexo); /*a funcao getche() eh mais apropriada 
para ler caracteres pertence a biblioteca conio.h */ 
 sexo=getche(); 
 sexo=toupper(sexo); /*toupper transforma em maiusculo o ca-
ractere pertence a biblioteca ctype*/ 
 switch (sexo) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
62 
 
 { case'F' : if (idade<=30) 
 mens=m*0.8; 
 else 
 if (idade>30 && idade<=40) 
 mens=m*0.7; 
 else 
 mens=m*0.65; 
 break; 
 case 'M' : if (idade<=25) 
 mens=m; 
 else 
 mens=m*0.75; 
 break; 
 default:printf("/nSexo invalido\n"); 
} 
printf("\nIdade: %i Mensalidade: %f",idade,mens); 
printf("\nInforme nome, para encerrar digite fim:\n"); 
fflush(stdin); /*libera a memoria do periférico de entrada pa 
 drao, pertence à biblioteca stdio.h */ 
 gets(nome); 
 t=strlen(nome); 
 for(x=0;x<t;x++) 
 nome[x]=toupper(nome[x]); 
 r=strcmp(nome,"FIM"); 
 } 
 return 0; 
} 
 
8.3.8 Exercício proposto 
1.0 Faça um programa que lê os seguintes dados relativos a 30 alunos de uma 
escola de futebol: nome; altura; data de nascimento (tarefa 1). O programa deverá 
fornecer como saída: a idade média dos alunos; a altura média dos alunos (tarefa 
2). 
 
 
9.0 Tipo Estruturado Heterogêneo (Registros ou Estruturas) 
Um registro é uma estrutura composta por um número fixo de componentes, cha-
mados campos. É um grupo de informações relativas a uma mesma entidade. 
Os campos do registro podem ser de diferentes tipos e a cada campo é dado um 
nome, (identificador do campo), o qual é utilizado para seleciona-lo. 
As estruturas são utilizadas para representar um conjunto de informações que es-
tão logicamente relacionadas; 
Por exemplo: 
 Uma ficha de cadastro de uma empresa que tem todo tipo de infor-
mações sobre um funcionário, necessárias para a empresa. 
 Uma ficha de um consultório médico que possui alguns dados e ca-
racterísticas do estado de saúde dos pacientes. 
 
 
9.1 Declaração 
 
Quando for necessário utilizar um registro é preciso definir um novo tipo: 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
63 
 
struct nome_do_novo_tipo 
{ tipo1 campo11, campo12, ..., campo1N; 
 tipo2 campo21, campo22, ..., campo2N; 
 ... 
 tipoM campoM1, campoM2, ... campo MN; }; 
 
Onde: 
 
nome_do_novo_tipo é o identificador que especifica o nome do registro criado 
(novo tipo de dados). A partir desse nome podem ser criadas variáveis desse tipo; 
 
tipo1, tipo2, tipo3, ... tipoM são os tipos de cada um dos campos do registro; 
 
campo11, campo12, ..., campoMN são os nomes dos campos do registro. 
Exemplos: 
 
 
 
 
struct fichaCadastral // declaração do tipo struct 
{ char cidade[41], estado[31], pais[21], dataNasc[11], 
nome[51],profissao[51], dataAdmissao[11], escolari-
dade[21]; 
int qtdeDependentes, numero, fumante; 
double salario; 
}; 
 
// declaração das variáveis do tipo criado 
struct fichaCadastral funcionario1, funcionario2; 
struct aluno 
{ char nome[20]; 
 char curso [25]; 
 float nota; 
}; 
 
Após a declaração da struct aluno é possível declarar variáveis do tipo criado: 
struct aluno a1, a2; 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
64 
 
Uma vez que o tipo de uma estrutura foi declarado, é possível utilizá-lo em outras 
declarações (variáveis simples, vetores, funções, etc). 
 
 
Exemplo: 
Struct aluno turma[55] 
 
Também é possível declarar logo ao final da declaração da estrutura as suas vari-
áveis, conforme mostra-se a seguir: 
 
struct reg_cliente // nome_da_estrutura 
{char nome[30]; //campos 
 float salario; 
 int idade; 
} cliente, fornecedor; //lista_de_variáveis 
 
Os campos de uma estrutura podem ser de qualquer tipo: tipos simples (int, char, 
float, etc), vetores, ou até mesmo estruturas: 
 
struct ponto 
 { int x; 
 int y; 
 }; 
 struct linha 
 { 
 struct ponto pa; 
 struct ponto pb; 
 } 
 
struct linha l1,l2; 
 
 
9.2 Acesso aos campos da estrutura 
 
O acesso aos campos é feito através do operador de associação – o ponto ( . ) 
 
a1.nome=”José Carlos dos Santos”; 
a1.curso=” Ciência da Computação”; 
a1.nota= 10; 
 
 
 
 
l1.pa.x=3.0; 
l1.pa.y=5.0; 
 l1.pb.x=15.0 
 l1.pb.y=5.0 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
65 
 
 
9.3 Atribuição entre variáveis do tipo struct 
 
É possível fazer atribuições entre variáveis de registro, porém elas devem ser do 
mesmo tipo struct declarado. 
a2=a1; 
l2 = l1; 
 
9.4 Matriz de estrutura 
 
É possível definir uma matriz do tipo estrutura: 
 
#include <stdio.h> 
struct conta { 
int num ; 
float saldo ; 
} ; 
void testeStruct(struct conta x[2]); 
int main() { 
struct conta c[2]; 
testeStruct(c) ; 
printf ("Main: Valor de c.num: %d\n", c[0].num) ; 
printf ("main: Valor de c.saldo: %.1f\n",c[0].saldo) ; 
printf ("Main: Valor de c.num: %d\n", c[1].num) ; 
printf ("main: Valor de c.saldo: %.1f\n",c[1].saldo) ; 
return 0; 
} 
void testeStruct (struct conta x[2]) { 
x[0].num = 2 ; 
x[0].saldo = 20.0 ; 
x[1].num = 3 ; 
x[1].saldo = 30.0 ; 
} 
 
9.5 Struct como retorno de uma função 
 
Uma função pode ter uma estrutura como valor de retorno: 
#include stdio.h 
struct ponto 
{ int x; int y; }; 
 
struct ponto constroiPonto(int x, int y; 
int main() 
{ struct ponto origem; 
 origem=constroiPonto(0,0); 
} 
struct ponto constroiPonto(int x, int y) 
{ struct ponto temp; 
 temp.x = x; 
 temp.y = y; 
 return temp; 
} 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
66 
 
9.6 Struct como parâmetro de função 
Uma struct pode ser passada como parâmetro para uma função, tanto na passa-
gem por valor, como por referencia. 
 
Na passagem por referencia devemos observar o acesso aos campos da mesma 
é feito através do operador "->" ao invés de "." 
 
Exemplo de passagem por referência de uma struct para uma função: 
 
#include <stdio.h> 
struct ponto 
{ int x; int y; 
}; 
void movep(struct ponto *p, int dx, int dy); 
int main() 
{ 
 struct ponto p1; 
 int i; 
 printf("Informe as coordenadas x e y do ponto:\n"); 
 scanf("%d%d",&p1.x,&p1.y); 
 movep(&p1,2,3); 
printf("nova coordenada x: %d nova coordenada y: 
%d",p1.x,p1.y); 
 return 0; 
} 
void movep(struct ponto *p1, int dx, int dy) 
{ p1 -> x += dx; 
 p1 -> y += dy; 
} 
 
 
9.7 Inicialização de uma variável do tipo struct 
Ao declararmos uma variável do tipo estrutura, podemos também definir o seu valor 
inicial, de forma análoga àquela utilizada para vetores. 
struct ponto origem = {0,0}; 
 
9.8 Ponteiros para structs 
 
A declaração é similar à declaração de um ponteiro para outros tipos de dados. 
Na implementação de estruturas de dados compostas por nodos ou células pon-
teiros para struct são bastante utilizados. Veja um exemplo no capítulo 16. 
 
9.9 Exercícios do tipo struct 
 
1. Fazer um programa que cria uma estrutura livro, que contém os elementos isbn 
(código internacional, um inteiro), ano de edição, número de páginas e preço. 
Criar uma variável desta estrutura que é um vetor de 5 elementos. Ler os valores 
para a estrutura e imprimir através de uma função a média do número de páginas 
do livros. 
 
2. Foi realizada uma pesquisa entre 500 habitantes de uma certa região. De cada 
habitante foram coletados os dados: idade, sexo, salário e número de filhos. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
67 
 
Construa um programa C que armazene as informações da pesquisa em um 
vetor de struct e utilize 1 função para realizar cada um dos itens: 
 Calcular a média salarial dos habitantes 
 Calcular a média de filhos. 
 Calcular o número de habitantes com salário inferior a média. 
 Listar os habitantes com mais de 3 filhos. 
3. Faça um programa para ler as seguintes informações relativas a 20 alunos da 
disciplina Programação Estruturada de um curso de Ciência da Computação: 
 Matrícula (inteiro) 
 Nota Final (real) 
 O programa deverá utilizar um vetor de struct para armazenar estas informações 
e, após lê-las, utilizar uma função para fornecer cada uma das informação 
abaixo: 
 A média da turma; 
 O total de alunos aprovados, considerando que estão aprovados os alunos 
com nota final >=7; 
 A matrícula do(s) alunos com maior Nota Final. 
 
4. Considerando o registro de um produto de uma loja contendo as seguintes in-
formações: descrição, valor, fornecedor, quantidade em estoque, fazer um pro-
grama que, considerando 50 produtos, utilize funções para: 
1. Ler as informações; 
2. Exibir as informações na ordem inversa em que foram digitados; 
3. Informar os produtos que têm menos de 2 unidades em estoque; 
4. Fornecer o total em reais (R$) que a empresa mantém com estes produtos. 
 
 
5. Elabore um programa para armazenar em um vetor de struct os dados de 80 
pessoas digitadas pelo usuário. Cada pessoa é caracterizada pelas seguintes 
informações: o seu nome (máximo de 30 caracteres), o seu peso e a sua idade. 
Utilize funções para : 
1. Cadastar as pessoas; 
2. Exibir o nome dos adolescentes, ou seja, pessoas com idade de 12 a 18 
anos; 
3. Exibir o(s) nome(s) da(s) pessoa(s) com o menor peso. 
 
 
6. Considerando a declaração da struct abaixo 
 
struct reg_cliente { 
char nome[30]; 
float salario; 
int idade; 
}; 
 
faça um programa para ler as informações de 30 clientes através de uma função e 
utilize outra função para retornar a main quantos clientes ganham mais de 
R$5.000,00 e não têm mais de 27 anos. 
 
7. Seja uma estrutura para descrever os carros de uma determinada revendedora, 
contendo os seguintes campos: 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
68 
 
marca: string de tamanho 15 
ano: inteiro 
cor: string de tamanho 10 
preço: real 
Faça um programa onde em main seja definido um menu para: 
a) acionar uma função para ler um vetor com no máximo 60 carros. 
b) acionar uma função que receba um preço e imprima os carros (marca, cor 
e ano) que tenham preço igual ou menor ao preço recebido. 
c) acionar uma função que leia a marca de um carro e imprima as informa-
ções de todos os carros dessa marca (preço, ano e cor).9.10 Exercícios resolvidos 
 
// exercício 2 
#include <stdio.h> 
#include <stdlib.h> 
#define MAX 3 
struct info 
{ int idade, nfilhos; 
 float salario; 
}; 
float media_sal(struct info pesquisa[MAX]); 
float media_filhos(struct info pesquisa[MAX]); 
int inferior_media (struct info pesquisa[MAX], float m_s); 
int mais_filhos (struct info pesquisa[MAX]); 
int main() 
{ 
 int x; 
 float m_s; 
 struct info pesquisa[MAX]; 
 char aux[20]; 
 printf("Informe os dados\n"); 
 for(x=0;x<MAX;x++) 
 { printf("Idade do habitante %d: ", x+1); 
/*scanf("%i",&pesquisa[x].idade); ler com gets e converter para 
inteiro, */ 
 gets(aux); 
 pesquisa[x].idade=atoi(aux); //converte char para int 
 fflush(stdin); //libera a memória de entrada de dados 
 printf("No. de filhos do habitante %d: ", x+1); 
 //scanf("%i",&pesquisa[x].nfilhos); 
 gets(aux); 
 pesquisa[x].nfilhos=atoi(aux); 
 fflush(stdin); 
 printf("Salario do habitante %d: ", x+1); 
 fflush(stdin); 
//scanf("%f",&pesquisa[x].salario); 
 gets(aux); 
 pesquisa[x].salario=atof(aux); //converte char para float 
 } 
 m_s = media_sal(pesquisa); 
 printf("media salarial: %.2f \n",m_s); 
 printf("media de filhos: %.2f \n", media_filhos(pesquisa)); 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
69 
 
 printf("numero de habitantes com salario abaixo da media sala-
rial: %d \n", inferior_media(pesquisa,m_s)); 
 printf("numero de habitantes com mais de 3 filhos: %d \n", 
mais_filhos(pesquisa)); 
 return 0; 
} 
// a média salarial dos habitantes 
float media_sal(struct info pesquisa[MAX]) 
{int x; 
 float m_sal; 
 m_sal=0; 
 for(x=0;x<MAX;x++) 
 m_sal+= pesquisa[x].salario; 
 m_sal=m_sal/MAX; 
 return (m_sal); 
} 
 
// a media de filhos. 
float media_filhos(struct info pesquisa[MAX]) 
{int x; 
 float m_fil; 
 m_fil=0; 
 for(x=0;x<MAX;x++) 
 m_fil+= pesquisa[x].nfilhos; 
 m_fil=m_fil/MAX; 
 return (m_fil);} 
// o numero de habitantes com salario inferior a media. 
int inferior_media (struct info pesquisa[MAX],float m_s) 
{int inferior , x; 
 inferior=0; 
 for(x=0;x<MAX;x++) 
 if (pesquisa[x].salario< m_s) 
 inferior++; 
 return(inferior); 
} 
// o total de habitantes com mais de 3 filhos. 
int mais_filhos (struct info pesquisa[MAX]) 
{int c=0,x; 
 for(x=0;x<MAX;x++) 
 if (pesquisa[x].nfilhos>3) 
 c++; 
 return(c); 
} 
 
 
 
/*Exercício 3 (demonstra passagem de struct por referência) */ 
 
#include <stdio.h> 
#include <stdlib.h> 
#define Max 3 
typedef struct { 
 int mat; 
 float nf; 
 int aprov; 
}aluno; 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
70 
 
int aprovado(aluno *al); 
int main () 
{ aluno v[Max],al; 
 char aux[15]; 
 int x,a,c=0; 
 fflush(stdin); 
printf("Informe a matricula e a nota final dos %i alu-
nos\n",Max); 
 for(x=0;x<Max;x++) 
 { gets(aux); 
 al.mat=atoi(aux); 
 fflush(stdin); 
 gets(aux); 
 al.nf=atof(aux); 
 fflush(stdin); 
 al.aprov=0; 
 a=aprovado(&al); 
 v[x]=al; 
 if(a) 
 c++; 
 } 
 printf("\ntotal de alunos aprovados: %i",c); 
 return 0; 
} 
int aprovado(aluno *al) 
{ int a=0; 
 if (al -> nf>=7) 
 { a=1; 
 al -> aprov=1; 
 } 
 return(a); 
} 
 
 
 
10.0 Métodos internos de ordenação 
 
Em processamento de dados lidamos com dois tipos de ordenação: interna e ex-
terna. Se a ordenação deve ser efetuada em um conjunto de elementos na memória 
do computador, dizemos tratar-se de ordenação interna. Quando os elementos a 
sererm ordenados, entretanto, está armazenados em arquivo, a ordenação é cha-
mada de externa. 
 
 
 
10.1 Método da Bolha (Bubble Sort ) 
 
É um dos métodos mais simples e conhecidos e baseia-se na troca de elementos. 
Consiste básicamente em : 
a)varrer a lista comparando cada elemento do vetor com todos os seus elementos 
seguintes; 
b)em cada comparação, verificar se estão invertidos, caso positivo, trocá-los de 
lugar; 
c)repetir os itens a e b até comparar os dois últimos elementos da lista. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
71 
 
Abaixo uma função que exemplifica a implementação do método: 
 
void bolha(int v2[ ]) 
{ int x,y,aux; 
 for(x=0;x<max-1;x++) 
 for (y=x+1;y<max;y++) 
 if (v2[x]>v2[y]) 
 { aux =v2[x]; 
 v2[x]=v2[y]; 
 v2[y]=aux; } 
} 
 
10.2 Método de ordenação por Seleção Direta 
É um pouco mais eficiente que o método Bubblesort. Em uma ordenação ascen-
dente, por exemplo, consiste em descobrir, a cada iteração, qual o menor elemento 
do vetor e colocá-lo na posição definitiva, iniciando o processo no primeiro ele-
mento. Com isto, a cada etapa teremos um segmento já ordenado e outro não or-
denado. 
 
Descrição do método: 
Inicialmente considera-se o segmento já ordenado como sendo formado pelo pri-
meiro elemento do vetor. Os demais elementos formam o segmento não orde-
nado.Pega-se, um a um, os elementos não ordenados, e por busca seqüencial da 
direita para a esquerda no segmento ordenado, localiza-se a sua posição correta, 
movendo-se os valores necessários. 
Continua-se este processo avançando no vetor da esquerda para a direita e a cada 
vez aumentando o segmento ordenado. 
vetor original: 
divisão inicial: 
ordenado não ordenado 
primeira iteração: 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
72 
 
 
 
Exemplo de Implementação : 
#include <stdio.h> 
#define Max 7 
int main() 
{ int v[Max], i, a, b, t; 
 printf("Digite os valores: "); 
 for(i=0;i<Max;i++) 
 scanf("%i",&v[i]); 
 for(a=1; a<Max; a++) 
 { t = v[a]; 
 for(b=a-1; b>=0 && t<v[b]; b--) 
 v[b+1] = v[b]; 
 v[b+1] = t; } 
 printf("Os valores ordenados:\n"); 
 for(i=0;i<Max;i++) 
 printf("%d ",v[i]); 
 return 0; 
} 
 
10.3- Método Shell 
 
Método criado por Donald Shell, consiste em comparar e trocar não elementos 
adjacentes, mas sim elementos separados por um certo intervalo. 
 
É derivado da ordenação por inserção e é baseado em iniciar a comparação entre 
elementos afastados por um intervalo maior que 1 e ir diminuindo progressiva-
mente este intervalo até atingir 1, que será p intervalo final. 
 
Como intervalo inicial pode considera-se a metade do número de elementos a or-
denar, mas não necessariamente. 
 
Referência: Martins, J. Pavão. Introdução à programação usando o Pascal. Portu-
gal: McGraw Hill , 1994. 
 
vetor original: 
divisão inicial: 
ordenado não ordenado 
primeira iteração: 
segunda iteração: 
terceira iteração: 
quarta iteração: 
quinta iteração: 
sexta iteração: 
Inclui elemento 15 no 
segmento ordenado 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
73 
 
Exemplo: 
Ordenar o vetor abaixo utilizando o método Shell, utilizando os intevalos 4, 2, 1: 
 
18 15 7 9 23 16 14 2 20 
Ordenação pelo 1º. Intervalo (4) 
18 15 7 9 23 16 14 2 20 
18 
 
23 
 
20 
9 15 7 14 20 16 18 2 23 
 
15 
 
16 
 
9 15 7 14 20 16 18 2 23 
 
7 
 
18 
 
9 15 7 14 20 16 18 2 23 
 
14 
 
2 
 
9 15 7 2 20 16 18 14 23 
 
20 
 
23 
9 15 7 2 20 16 18 14 23 
 
 
 
Ordenação pelo 2º. Intervalo (2): 
9 15 7 2 20 16 18 14 23 
97 
 
20 
 
18 
 
23 
7 15 9 2 18 16 20 14 23 
 
15 
 
2 
 
16 
 
14 
 
7 15 2 9 18 14 20 16 23 
 
2 
 
18 
 
20 
 
23 
7 15 2 9 18 14 20 16 23 
 
9 
 
14 
 
16 
 
7 15 2 9 18 14 20 16 23 
 
18 
 
20 
 
23 
7 15 2 9 18 14 20 16 23 
 
14 
 
16 
 
7 15 2 9 18 14 20 16 23 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
74 
 
Ordenação final (intervalo igual a 1): 
7 15 2 9 18 14 20 16 23 
7 15 
 
7 15 2 9 18 14 20 16 23 
 
15 2 
 
2 7 15 9 18 14 20 16 23 
 
15 9 
 
2 7 9 15 18 14 20 16 23 
 
15 18 
 
2 7 9 15 18 14 20 16 23 
 
18 14 
 
2 7 9 14 15 18 20 16 23 
 
18 20 
 
2 7 9 14 15 18 20 16 23 
 
20 16 
 
2 7 9 14 15 16 18 20 23 
 
20 23 
2 7 9 14 15 16 18 20 23 
 
A eficácia deste algoritmo deriva do comportamento natural do método de Inserção. 
Os primeiros passos irão “preparar o terreno”, ou seja tornarão o vetor muito pró-
ximo do estado final, restando poucas comparações e trocas para o último passo. 
 
A seqüência exata para divisão em segmentos decrescentes pode variar, a única 
regra é que o último deve ser 1. 
Por exemplo, a seqüência pode ser : h=9, h=5, h=3, h=2, h=1 
 
Exemplo de implementação do método Shell: 
 
#include <string.h> 
#include <stdlib.h> 
#include <ctype.h> 
void shell(char *item, int count); 
int main() 
{ char s[80]; 
 int l,i; 
 printf("Digite uma string: "); 
 gets(s); 
 l=strlen(s); 
 for(i=0;i<l;i++) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
75 
 
 s[i]=toupper(s[i]); 
 shell(s, strlen(s)); 
 printf("A string ordenada: %s\n", s); 
 return 0; 
} 
 
void shell(char *item, int count) 
{ int i, j, gap, k; 
 char x, a[5]; 
 a[0]=9; a[1]=5; a[2]=3; a[3]=2; a[4]=1; 
 for(k=0; k<5; k++) 
 { 
 gap = a[k]; 
 for(i=gap; i<count; ++i) 
 { 
 x = item[i]; 
 for(j=i-gap; x<item[j] && j>=0; j=j-gap) 
 item[j+gap] = item[j]; 
 item[j+gap] = x; 
 } 
 } 
} 
 
 
10.4 Método Quicksort 
 
Algoritmo de alta eficiência criado por C. A. R. Hoare em 1960 e conhecido tam-
bém como método de ordenação por partição. 
 
Sua idéia central é dividir o conjunto inicial de valores a ordenar em dois conjuntos 
menores que são ordenados independentemente. O método consiste basicamente 
de duas etapas: partição e ordenação. 
 
1- Partição: nesta fase é feito o rearranjo do conjunto de valores através da 
escolha arbitrária de um dos seus itens (chamado de pivô, ou mediana) de tal forma 
que ao final desta etapa todos os elementos menores ou iguais ao pivô estejam a 
sua esquerda e todos os maiores (ou iguais) a sua direita, estando então o pivô 
posicionado de forma adequada. 
 
No exemplo abaixo foi escolhido para pivo um elemento central ao conjunto de va-
lores. 
 
Após a determinação do pivô o vetor começa a ser percorrido pela esquerda e pela 
direita por dois apontadores, (i e j), sendo trocados de posição os elementos que 
estejam fora da posição relativamente ao valor do pivô; 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
76 
 
 
 
2- A próxima etapa (ordenação) consiste em aplicar o mesmo processo para 
ambas as partições e, em seguida para cada uma das partições obtidas, até que 
cada uma possua apenas um elemento. 
 
No algoritmo apresentado abaixo, que é uma solução iterativa do método quick-
sort, é mantida uma lista de pedidos de particionamentos que ainda devem ser 
executados. Após cada passo surgem duas tarefaa de particionamento e somente 
uma poderá ser resolvida na iteração que segue ficando a outra empilhada na lista. 
Utiliza-se uma pilha porque as tarefas que ficam aguardadndo resolução devem ser 
atendidas na ordem inversa. 
 
Programa QuickSort; 
Const 
 n=7; 
estrutura marcadores{ 
 esq, dir: inteiro; }; 
estrutura marcadores pilha[n]; 
inteiro v[n]; 
inteiro i,j,x,y,w,l,r,s; 
Inicio 
 Para i←0 a n faça 
 leia(v[i]); 
 s ← 0; 
 pilha[s].esq ← 0; 
 pilha[s].dir ← n-1; 
Repita 
 l ← pilha[s].esq; 
 r ← pilha[s]. dir; 
 s ← s -1; 
 Repita 
 i ← l; 
 j ← r; 
 x ← v[ (l+r) / 2]; 
 Repita 
 Enquanto v[i]<x faça 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
77 
 
 i ← i+1; 
 Enquanto v[j]>x faça 
 j ← j-1; 
 Se i<=j então 
 Inicio 
 w ← v[i]; 
 v[i] ← v[j]; 
 v[j] ← w; 
 i ← I+1; 
 j ← j-1; 
 Fim; 
 Até i>j; 
 Se i<r então 
 Inicio 
 s ← s+1; 
 pilha[s].esq ← i; 
 pilha[s].dir ← r; 
 Fim; 
 r ← j; 
 Até l >= r; 
Até s <0; 
 
O método quicksort usualmente é implementado na forma recursiva, o que será 
visto dentro do assunto recursividade. 
Referências: 
WIRTH, Niklaus. Algoritmos e estruturas de dados. Rio de Janeiro: Prentice-
Hall,1989. 
ZIVIANI, Nivio. Projeto de Algoritmos com implementações em Pascal e C. São 
Paulo: Pioneira, 1999. 
 
 
11.0 Métodos internos de Pesquisa 
 
11.1 Pesquisa Seqüencial: Verifica cada elemento do vetor, seqüencialmente, até 
que o valor seja encontrado, ou que todos os elementos do vetor tenham sido 
verificados. 
 
 
11.2 Pesquisa Binária 
É mais rápida que a pesquisa seqüencial e iIdeal para listas com grande número 
de elementos. 
 
Descrição do Método: 
1- Os elementos da lista devem estar em ordem crescente; 
2- Localizar o elemento do meio; 
3- Se ele for igual ao elemento procurado, a pesquisa é dita bem sucedida e inter-
rompida; 
4- No caso de ser maior repete-se o processo (2-3) na primeira metade do vetor; 
5- Caso seja menor, repete-se o processo na segunda metade do vetor. 
6- Este procedimento é continuado até que o elemento seja localizado ou então, 
até que não reste mais um trecho do vetor a ser pesquisado. 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
78 
 
#include <stdio.h> 
#define max 10 
void le_vetor(int v[]); 
int le_valor(); 
int pesq_bin(int v[],int num); 
void ordena(int v[]); 
 
int main() 
{ 
 int v[max], num,p; 
 le_vetor(v); 
 num=le_valor(); 
 ordena(v); 
 p=pesq_bin(v,num); 
 if (p>=0) 
 printf("Encontrado na posição %i 
 \n",p); 
 else 
 printf("Nao foi encontrado\n"); 
 return 0; 
} 
void le_vetor(int v[]) 
{ int x; 
 for (x=0;x<max;x++) 
 { printf("Digite o elem %d: ",x+1); 
 scanf("%d",&v[x]); 
 } 
} 
 
int le_valor() 
{ int n; 
 printf("Digite o valor a procurar:"); 
 scanf("%d",&n); 
 return n; 
} 
 
void ordena(int v2[ ]) 
{ 
 int x,y,aux; 
 for(x=0;x<max-1;x++) 
 for (y=x+1;y<max;y++) 
 if (v2[x]>v2[y]) 
 { aux=v2[x]; 
 v2[x]=v2[y]; 
 v2[y]=aux; 
 } 
} 
 
int pesq_bin(int v1[],int n) 
{ int comeco,meio,fim,x=-1; 
 comeco=0; 
 fim=max-1; 
 while (comeco<=fim) 
 { meio=(comeco+fim)/2; 
 if (n==v1[meio]) 
 { x=meio; 
 comeco=fim+1; 
 } 
 else 
 { if (n<v1[meio]) 
 fim=meio-1; 
 else 
 comeco=meio+1;} 
 } 
 return (x); 
} 
 
 
11.3 Exercício proposto 
 
1. Faça um programa quelê os seguintes campos de uma estruct, relativos a 
uma turma com 60 alunos: nome, altura,data de nascimento. O programa deverá 
apresentar um menu que permita fornecer: 
a) a média das idades, 
b) o nome do aluno mais alto; 
c) listagem apresentando idades em ordem decrescente e os respectivos nomes 
dos alunos. 
d) pesquina de aluno por nome. 
Utilize uma função para obter cada uma das saídas desejadas. 
 
 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
79 
 
12.0 Recursividade 
A recursão é uma técnica pela qual uma rotina estruturada faz chamadas a ela 
mesma, com o objetivo de completar uma tarefa repetitiva e que pode ser identifi-
cada como uma tarefa recursiva, pois nem todas as tarefas repetitivas podem ser 
resolvidas através de recursão. 
 
12.1 Definições 
Dizemos que a solução de uma tarefa é recursiva quando pode ser definida em 
termos de si mesma, definindo uma tarefa mínima e uma condição de parada. 
Um exemplo bastante intuitivo é a tarefa “subir uma escada”. 
 
 
 
 
 
Observe que, a tarefa “subir a escada”pode ser decomposta em uma repeti-
ção finita da tarefa “subir um degrau”, até atingir a condição de parada 
Um outro exemplo típico de problema que pode ser resolvido de forma recursiva é 
o cálculo do fatorial de um número, onde, por definição teremos: n ! = n * (n-1)! 
Sendo N um inteiro, temos: 
 
0 ! = 1 
1 ! = 1 * 0 ! = 1*1 
2 ! = 2 * 1 ! = 2 * 1 * 1 
3 ! = 3* 2 ! = 3 * 2 * 1 * 1 
n ! = n * (n-1)! = n*(n-1)*(n-2)* …* 1 
 
Que pode ser formulado como uma 
função: 
 
 1 se N = 0; 
N ! = 
 N * ( N-1 ) ! se N > 0 
 
 
 
Esta definição nos possibilita formular uma função recursiva para cálculo do fato-
rial de um dado número n, inteiro: 
 
int fat (int n) 
{ if (n==0 ) 
 return 1; 
 else 
 return n*fat(n-1); } 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
80 
 
A condição de parada e a tarefa mínima, neste caso, foram encontradas na própria 
definição da função fatorial: 
 
Condição de parada (caso base) : 
 
0 ! = 1 
Tarefa mínima (caso recursivo) : 
 
N! = N*(N -1)! 
 
É importante observar que a cada chamada feita à função Fat, a dimensão do pro-
blema (N) diminui, até atingir a condição de parada (N=0), o que é indispensável 
para limitar a execução revursiva da função. 
 
Pode-se então definir como Regras da Recursividade: 
 
 Um subprograma recursivo deve ter pelo menos uma condição de pa-
rada; 
 Cada chamada recursiva deve ocorrer de modo que sua execução ca-
minhe em direção ao caso base. 
 
Para controlar o retorno às linhas de instrução (e os valores dos parâmetros da 
função) que deixaram de ser executadas, devido ao desvio provocado pela cha-
mada recursiva, o compilador mantém uma pilha de execução. 
Esta pilha guarda o endereço e o valor da variável antes da nova chamada. Estes 
são os chamados “processos suspensos” que ficam aguardando até poderem se 
completar. 
 
A figura a seguir mostra um exemplo, considerando N=3 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
81 
 
 
 
Outro exemplo de solução recursiva: Soma de n números naturais a partir de 1 
 
#include <stdio.h> 
#include <stdlib.h> 
 
/*Faça um programa para calcular a soma de todos os números pertencentes 
ao conjunto dos naturais, menos o zero, menores ou iguais a um dado 
valor n, também natural */ 
int soma(int n); 
int main() 
{ int n,s,x; 
printf("Digite um valor inteiro posit e diferente de zero \n"); 
 scanf("%i",&n); 
 /* s=n; 
 * for (x=1;x<n;x++) 
 * s=s+x; */ 
 printf("A soma é: %i \n", soma(n)); 
 return 0; 
} 
int soma(int n) 
{ if(n==1) 
 return n; 
 else 
 return n+soma(n-1); 
} 
 
 
Um algoritmo que é resolvido classicamente através de recursividade é o método 
de ordenação quick sort, abaixo um exemplo de sua implementação: 
 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
void quick(char *item, int count); 
void qs(char *item, int left, int right); 
 
int main() 
{ char s[80]; 
 printf("Digite uma string: "); 
 gets(s); 
 quick(s, strlen(s)); 
 printf("A string ordenada: %s\n", s); 
 return 0; 
} 
void quick(char *item, int count) 
{ qs(item, 0, count-1); 
} 
void qs(char *item, int left, int right) 
{ int i, j; 
 char x, y; 
 i = left; j = right; 
 x = item[(left+right)/2]; 
 do 
 { while(item[i]<x && i<right) i++; 
 while(x<item[j] && j>left) j--; 
 if(i<=j) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
82 
 
 { y = item[i]; 
 item[i] = item[j]; 
 item[j] = y; 
 i++; 
 j--; 
 } 
 } while(i<=j); 
 if(left<j) qs(item, left, j); 
 if(i<right) qs(item, i, right); 
} 
 
12.2 Exercícios propostos 
 
 Faça um programa que calcula, através de uma função recursiva, a potência 
de um número, sendo lidos no programa principal a base e a potência. 
 Faça um programa para calcular recursivamente o valor de um termo N da 
Série de Fibonatti,sabendo que o primeiro termo da série é 1, o segundo termo da 
série também é 1 e partir destes todos os termos seguintes são formados pela soma 
dos dois anteriores: 
 
 
 
 
13.0 Operações em meio magnético - Arquivos 
 
Os arquivos são usados para armazenar, de forma permanente, grandes quantida-
des de dados. O armazenamento é feito em memória secundária. 
 
O sistema de arquivos em C é projetado para trabalhar com diversos dispositivos 
(terminais, acionadores de disco, de fita, etc) e para tratar a informação de forma 
semelhante, apesar das diferenças entre os dispositivos, o sistema com buffer 
adota um dispositivo lógico, chamado stream. 
Assim, streams são independentes dos dispositivos e a mesma função poderá es-
crever em um arquivo em disco ou em outro dispositivo de saída. 
Existem dois tipos de streams: Binárias e Texto 
 
Streams de Texto: 
 Uma seqüência de caracteres, organizada em linhas. 
 As linhas são separadas por um único caractere, chamado caractere de 
nova linha (ou LF) cujo código ASCII decimal é 10. 
 Números são guardados como cadeias de caracteres. 
 
Streams Binárias: 
 Uma seqüência de bytes. 
 Não há indicador de fim de arquivo. 
 Números são guardados como na memória (2 bytes para inteiro, 4 bytes 
para float, etc.) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
83 
 
 
 
A linguagem C possibilita duas diferentes categorias de acesso a disco: 
 
Alto Nível – acesso a arquivos através de um pacote de funções permitindo 4 mo-
dos diferentes: 
1. Dados lidos e escritos um caractere por vez; 
2. Dados lidos e escritos como “strings”; 
3. Dados lidos e escritos de modo formatado; 
4. Dados lidos e escritos em formato de registro (ou bloco) que 
possui um tamanho fixo, como matrizes e estruturas. Tem-se 
assim uma arquivo formado por uma sequencia de itens com 
mesmo tamanho. 
 
Baixo Nível – apenas as funções read() e write() 
Em nosso curso abordaremos somente o acesso de alto nível. 
 
 
13.1 Definição do tipo file 
Programas criados para trabalhar com arquivos envolvem a implementação de, 
pelo menos, três etapas: criação ou abertura do arquivo, gravação ou leitura de 
informações no arquivo e fechamento do arquivo. 
 
Na primeira etapa, caso o arquivo nunca tenha sido criado, isto deverá ser feito, 
caso contrário, deverá ser aberto para inclusões, leituras, alterações, exclusões,etc. 
 
Já na segunda etapa utilizam-se funções definidas na linguagem para trabalhar 
com os dados existentes no arquivo e/ou anexar novos dados. 
 
Na terceira etapa é feito o fechamento do arquivo e aí garantimos que todas as 
operações implementadas na segunda etapa sejam efetivamente realizadas. 
 
Um arquivo possue sempre um nome que o identifica no meio externo, porém no 
código do programa necessitamos uma variável específica que represente a estru-
tura do arquivo. A biblioteca stdio.h contém a declaração de uma estrutura cha-
mada FILE que guarda as informações necessárias para que possamos trabalhar 
com arquivos nos nossos programas em C. 
 
As variáveis do tipo FILE diferem de todas as outras pelo fato de estarem associa-
das a arquivos em disco. 
Enquanto uma variável do tipo FILE só existe durante a execução de um pro-
grama, o arquivo que lhe está associado pode existir antes da execução de um 
programa e manter a sua existência em disco após o término da sua execução. 
 
Quando trabalharmos com arquivos, portanto, haverá sempre a necessidade de ser 
feita a declaração de uma variavel ponteiro para a estrutura FILE, como mostra o 
exemplo a seguir. Muitas funções que fazem parte do sistema de arquivos do C 
ANSI retornam um ponteiro desta variável para relacionar uma stream com um ar-
quivo. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
84 
 
 
#include <stdio.h> 
int main() 
{ 
 FILE *fptr ; 
 fptr = fopen("exemplo.dat", "w") ; 
 . . . 
 . . . 
 fclose(fptr) ; 
 } 
 
No trecho de código do exemplo, são mostradas as duas funções sempre neces-
sárias ao implementarmos arquivos, que correspondem à primeira e última etapas, 
citadas no inicio deste tópico. A função fopen (utilizada para abrir um arquivo), 
retorna um ponteiro para o arquivo aberto que fica armazenado em fptr. Ao finalizar 
o arquivo é necessário fechá-lo e é utilizada a função fclose, sendo seu parâmetro 
a mesma variável, associada ao tipo File. 
 
 
13.2 Estrutura básica de um arquivo: 
Um arquivo consiste em uma seqüência de componentes de um mesmo tipo. O 
número de componentes (registros) de um arquivo não é determinado na definição 
do arquivo, sendo que o compilador C vai alocando espaço conforme for necessá-
rio, através de um apontador de registros no arquivo. 
 
Cada vez que um componente é escrito em um arquivo ou lido de um arquivo, o 
apontador do arquivo (indicador de posição de registro) avança para o próximo 
componente, ficando assim já prosicionado para uma próxima inserção ou leitura 
no arquivo, de forma sequencial. 
 
Em C os arquivos são tratados como de organização seqüencial, porém é permitido 
que arquivos binários sejam acessados tanto na forma seqüencial como na forma 
randômica (acesso direto), o que fazemos utilizando procedimentos e funções exis-
tentes na linguagem. 
Se todos os registros de um arquivo são de mesmo comprimento, a posição cor-
respondente a cada registro pode ser calculada e o indicador de registro movimen-
tado para esta posição, obtendo-se desta maneira o acesso direto. 
 
 
13.3 Funções para tratamento de arquivos em alto nível 
 
13.3.1 Abertura e fechamento de arquivo 
 
Função fopen - abertura de arquivo 
Antes de podermos realizar operações em um arquivo, (por exemplo, inserir um 
registro, consultar, alterar, excluir) é necessário a abertura de uma stream e sua 
associação com um arquivo. 
Isto é feito com o comando fopen que tem o seguinte protótipo: 
 
Declaração: FILE *fopen (char *nomearq, char *modo); 
Biblioteca: stdio.h 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
85 
 
O parâmetro nomearq é uma string de caracteres que contém o nome do arquivo 
desejado. O parâmetro modo especifica como será usado o arquivo - para ler, gra-
var ou anexar. 
 
A função fopen() executa duas tarefas: 
1) preenche a estrutura FILE com as informações necessárias para o programa 
e para o sistema operacional, assim eles podem se comunicar; 
2) retorna um ponteiro do tipo FILE que aponta para a localização na me-
mória da estrutura FILE. 
 
 
 
 
São possíveis três tipos de abertura: 
 “r” para leitura 
 “w”para gravação 
 “a” para adicionar dados 
Existem modificadores para os tipos de abertura: 
1- acrescenta-se a letra “b” para indicar que o tipo do arquivo é binário 
2- acrescenta-se o sinal “+” quando o arquivo já existe e queremos atualizá-lo 
 
A tabela abaixo mostra os modos válidos e seus modificadores: 
 
 
 
 
Se o arquivo não puder ser aberto, fopen() devolve NULL. É usual utilizar o retorno 
para encerrar o procedimento evitando erros de abertura, como mostra o trecho de 
código a seguir: 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
86 
 
#include <stdio.h> 
#include <conio.h> 
int main() 
{ 
 FILE *fptr; 
 int ch; 
 if ((fptr=fopen("arqtext.txt","r"))==NULL) 
 { printf("Impossivel abrir o arquivo"); 
 exit(); //encerra o programa e fecha todos os arqui-
vos 
 } 
} 
Devemos sempre considerar que ao realizar a abertura de um arquivo o localizador 
de registros se posiciona no seu início. 
 
Função fclose() - fechamento de arquivo 
Sintaxe: int fclose (FILE *fp); 
Biblioteca: stdio.h 
 
Observação: Retorna 0 se a operação foi bem sucedida. 
Ao finalizar as operações em um arquivo este deve ser fechado, pois com isto al-
guma informação que tenha ficado no “buffer”, associada ao fluxo de saída, é gra-
vada. 
Mas, o que é este "buffer"? 
Quando enviamos caracteres para serem gravados em um arquivo, estes caracte-
res são armazenados temporariamente em uma área de memória (o "buffer") em 
vez de serem escritos em disco imediatamente. Quando o "buffer" estiver cheio, 
seu conteúdo é escrito no disco de uma vez. A razão para se fazer isto tem a ver 
com a eficiência nas leituras e gravações de arquivos. Se, para cada caracter que 
fossemos gravar, tivéssemos que posicionar a cabeça de gravação em um ponto 
específico do disco, apenas para gravar aquele caracter, as gravações seriam 
muito lentas. Assim estas gravações só serão efetuadas quando houver um volume 
razoável de informações a serem gravadas ou quando o arquivo for fechado. 
O fechamento libera também, para reaproveitamento, a área utilizada pela estrutura 
FILE. 
 
13.3.2 Função sinalizadora de final de arquivo – EOF() 
 
Sintaxe: int feof (FILE *fp); 
Biblioteca: stdio.h 
A função feof() informa se o fim de arquivo foi encontrado. Devolve 0 se não chegou 
ao fim do arquivo. 
14.3.3 Função rewind() 
 
 
Sintaxe: void rewind (FILE *fp); 
Biblioteca: stdio.h 
Movimenta o localizador de registros para o inicio do arquivo. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
87 
 
13.3.4 Escrita e leitura de um caractere em arquivo texto 
 
putc() : grava um caractere por vez no arquivo. 
 
Sintaxe: int putc (int ch, FILE *fp); 
Biblioteca: stdio.h 
Se uma gravação for bem sucedida putc() devolverá o caracter gravado, caso con-
trário devolverá um EOF (fim de arquivo). 
 
 
getc() : Lê no arquivo um caractere de cada vez. 
Sintaxe: int getc (FILE *fp); 
Biblioteca: stdio.h 
Sempre, após a escrita de um caractere ou a leitura de um caractere o sinalizador 
de registros ficará posicionado para nova gravação ou leitura em sequencia. 
ch é o caracter a ser gravado 
fp é o ponteiro do arquivo aberto pela função fopen() 
 
Exemplo para leitura e gravação de um caractere em arquivo texto: 
 
#include <stdio.h> 
int main() 
{ FILE *fptr; 
 int ch; 
 if ((fptr=fopen("arqtext.txt","w+"))==NULL) 
 { printf("Impossivel abrir o arquivo"); 
 exit(); // encerra o programae fecha todos os arquivos 
 } 
 printf("Digite o texto (<enter> encerra)\n"); 
 while ((ch=getche()) != '\r') //enquanto ch diferente de enter 
 putc(ch,fptr); //grava no arquivo 
 rewind(); //reposiciona o localizador de posição de arquivo 
no inicio do arquivo 
 printf("Este é o texto gravado no arquivo:\n"); 
 while((ch=getc(fptr)) != EOF) 
 printf("%c",ch); 
 fclose(fptr); 
 return 0; 
} 
 
 
Arquivos são uma sequencia de informações e é possível deslocar-se dentro desta 
sequencia de dados. Sempre que abrimos um arquivo (para leitura ou gravação) 
ficamos posicionados no seu inicio e sempre após a realização de cada operação 
nos movemos uma posição à frente, o que caracteriza um acesso seqüencial aos 
dados. Para ler as informações gravadas no arquivo texto, precisamos retornar ao 
inicio do arquivo. Este é o motivo de usar o comando rewind() no exemplo acima, 
ele coloca o localizador de registros no início do arquivo. 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
88 
 
13.3.5 Escrita e leitura de uma string em um arquivo texto 
 
fputs(): função utilizada quando é preciso gravar uma sequencia de caracteres em 
um arquivo. 
Sintaxe: char *fputs (char *str, FILE *fp); 
Biblioteca: stdio.h 
 
 
fgets(): usada para ler uma seqüencia de caracteres de um arquivo. 
Sintaxe: char *fgets (char *str, int comprimento, FILE *fp); 
Biblioteca: stdio.h 
 
A função fgets identifica o fim de uma string através do '\n' 
 
 
Com estes comandos sempre, após a gravação ou a leitura de uma string, o 
sinalizador de registros fica posicionado para nova gravação ou leitura de outra 
string, em sequencia. 
 
Exemplo: 
//exemplifica leitura e gravacao de strings 
#include <stdio.h> 
int main () 
{ FILE *fptr; 
 char linha[81]; 
 if ((fptr = fopen("teste.txt","w+"))==NULL) 
 { printf("Impossivel abrir o arquivo"); 
 exit(); // encerra o programa e fecha todos os arquivos 
 } 
 printf("Digite o texto (tecle <enter> em nova linha p/ encer-
rar)\n"); 
while (strlen(gets(linha))>0) 
 {fputs(linha,fptr); //grava a linha lida no arquivo 
 fputs("\n", fptr); // grava o sinal de fim de linha 
 } 
 rewind(fptr); 
 printf("Este eh o texto gravado no arquivo:\n"); 
 while((fgets(linha,80,fptr)) != NULL) 
 printf("%s",linha); //escreve na tela 
 fclose(fptr); 
 return 0; 
} 
 
 
 13.3.6 Escrita e leitura de dados formatados 
Estes comandos são utilizados quando necessitamos gravar dados numéricos em 
arquivos. 
 
fprintf() - função para gravação de dados formatados 
Sintaxe: int fprintf (FILE *fp, char *formato, lista argumentos); 
Biblioteca: stdio.h 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
89 
 
fscanf() – função para leitura de dados formatados. 
Sintaxe: int fscanf (FILE *fp, char *formato, lista argumentos); 
Biblioteca: stdio.h 
 
A função fscanf devolve o valor EOF se chegou ao fim do arquivo antes de ler 
uma variável solicitada. 
 
 
Podemos relacionar fprintf com printf e também fscanf com scanf, pois todas se 
comportam de forma semelhante, exceto pelo fato de que fprintf e scanf operam 
com arquivos em disco. 
 
Exemplo para gravação e leitura formatada: 
 
/* faca um programa que grava o nome, o no. de registro e o preco de livros em um 
arquivo até o usuario digitar fim para nome. A seguir apresenta os dados gravados*/ 
#include <stdio.h> 
 
int main() 
{ FILE *fptr; 
 char titulo[30]; 
 int regnum; 
 float preco; 
 if ((fptr=fopen("text.txt","w+"))==NULL) 
 { printf("Impossivel abrir o arquivo"); 
 exit(); 
 } 
 printf("\nDigite o titulo do livro (fim encerra):"); 
 scanf("%s",titulo); 
 while(strcmp(titulo, "fim")!=0) 
 { printf("\nDigite o no. do registro:"); 
 scanf("%d",&regnum); 
 printf("\nDigite o preco:"); 
 scanf("%f",&preco); 
 fprintf(fptr,"%s %d %f",titulo, regnum, preco); 
 printf("\nDigite o titulo do livro (fim encerra):"); 
 scanf("%s",titulo); 
 } 
 rewind(fptr); 
 while(fscanf(fptr,"%s %d %f",titulo,&regnum,&preco)!=EOF) 
 printf("%s %3d %f\n", titulo, regnum, preco); 
 fclose(fptr); 
 return 0; 
 } 
 
13.3.7 Funções para leitura e gravação de blocos de dados e implementação 
de arquivos binários. 
 
Existem funções apropriadas para realizar leitura e gravação de estruturas (regis-
tros e matrizes) que se caracterizam por ser um bloco de dados, sempre com o 
mesmo tamanho. Arquivos destas estruturas podem ser implementados com for-
mato binário, ao invés de texto. A vantagem está em que um arquivo binário ocupa 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
90 
 
bem menos espaço em disco, já que armazena os dados em forma binária, ou seja, 
como eles estão armazenados na memória do computador. 
 
Em C os arquivos binários são tratados como de organização seqüencial, sendo 
que cada vez que um componente é escrito em um arquivo ou lido de um arquivo, 
o apontador do arquivo (indicador de registro) avança para o próximo componente, 
ficando assim já prosicionado para uma próxima inserção ou leitura no arquivo, de 
forma sequencial. É permitido, porém que sejam criados arquivos com acesso tanto 
na forma seqüencial como na forma randômica (acesso direto). 
No acesso seqüencial os registros vão sendo gravados sequencialmente, um após 
o outro a partir da primeira posição, que é a poisição zero(0). Para acessar um 
determinado registro devemos nos posicionar no inicio do arquivo e fazer uma 
busca seqüencial no mesmo. 
 
Considerando que todos os registros de um arquivo de bloco de dados são de 
mesmo comprimento, a posição correspondente a cada registro pode ser calculada 
e o indicador de registro movimentado para esta posição, obtendo-se desta maneira 
o acesso direto. A função que permite deslocar o apontador de registros no arquivo 
é a função fseek(), que será vista a seguir. 
 
No acesso direto, os registros são gravados também sequencialmente porém im-
plementa-se de tal forma que, antes de gravar cada registro, o apontador (ou loca-
lizador de registros) é levado para uma determinada posição no arquivo (geral-
mente definida por um campo de tipo inteiro da struct e que que seja uma chave 
primária das informações). 
 
Para fazer o acesso direto a um registro bastará, então, posicionar o localizador 
segundo a chave primária com que foi posicionado na gravação e ler o registro. 
 
O acesso é mais rápido, porém, durante a gravação, a cada vez que o apontador 
de registros é deslocado, “saltando posições” no arquivo, estas são ocupadas com 
“lixo” o que dificulta um posterior aproveitamento destes espaços no arquivo. 
 
É usual então que se faça uma inicialização dos registros no arquivo colocando em 
determinado campo um controle, para indicar que aquela posição do arquivo está 
“livre”. 
 
 
 
 13.3.7.1 Função fseek() - permite deslocar o apontador de registro no arquivo 
para uma posição específica. 
 
 Sintaxe: int fseek (FILE *fptr, long int num_bytes, int origem); 
 Biblioteca: stdio.h 
 
num_bytes: É o número de bytes desde a origem até chegar à posição desejada. 
 
 
A tabela a seguir mostra os três valores possíveis para origem: 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
91 
 
Origem Identificador 
Início do arquivo SEEK_SET 
Posição corrente SEEK_CUR 
Fim do arquivo SEEK_END 
 
 
Para mover o apontador “num_bytes” a partir da origem utiliza-se SEEK_SET, 
para movê-lo a partir da posição que se encontra utiliza-se SEEK_CUR e para mo-
ver-lo a partir do final doarquivo usa-se SEEK_END. 
A função fseek() retorna zero se for bem sucedida e um valor diferente de zero se 
houver erro. 
 
Exemplo: 
struct l 
 { char titulo[30]; 
 int regnum; 
 double preco; 
 }; 
FILE * fptr; 
struct l livro; 
fseek((fptr, 9*sizeof(struct l), SEEK_SET); 
 
O comando fseek do trecho de código acima, irá posicionar o apontador de registros 
na 9ª. posição no arquivo 
 
 
13.3.7.2 Função ftell() – retorna a posição do apontador de registros em rela-
ção ao início do arquivo 
 
Sintaxe: long ftell (FILE *fptr); 
Biblioteca: stdio.h 
 
 
13.3.7.3 Funções fread() e fwrite() – leitura e gravação de blocos de dados 
As funções fread e fwrite são utilizadas para ler e gravar blocos de dados, usual-
mente uma struct. 
 
fread(): Leitura de blocos 
Sintaxe: int fread (void *buffer, int num_bytes, int cont, FILE *fptr); 
Biblioteca: stdio.h 
Devolve o número de itens (blocos) lidos, o valor de cont portanto. Se encontrar o 
fim do arquivo ou ocorrer um erro devolverá um valor menor que cont. 
 
fwrite():Gravação de blocos 
Sintaxe: int fwrite (void *buffer, int num_bytes, int cont, FILE *fptr); 
Biblioteca: stdio.h 
Devolve o número de itens (blocos) gravados, o valor de cont portanto. Se encon-
trar o fim do arquivo ou ocorrer um erro devolverá um valor menor que cont. 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
92 
 
buffer: É um ponteiro para a região da memória ou o endereço de uma variável 
que receberá os dados lidos do arquivo pela função fread ou que será gravada no 
arquivo pela função fwrite. 
num_bytes: Especifica a quantidade de bytes a serem lidos ou gravados. 
cont: Determina quantos blocos (cada um com comprimento de num_bytes) serão 
lidos ou gravados. 
fptr: É o ponteiro para o arquivo. 
 Este modo grava números no formato binário 
 Permite gravar qualquer quantidade de dados de uma vez (mais de 1 bloco 
por vez); 
 Uma simples instrução pode gravar matrizes, estruturas, matrizes de estrutu-
ras e outras. 
 
 
Exemplo de gravação de 01 bloco de dados: 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
 struct 
 { char titulo[30]; 
 int regnum; 
 double preco; 
 } livro; 
 FILE * fptr; 
 fptr = fopen ("livros.rec","wb"); 
 if (fptr == NULL) 
 { printf("\nErro na abertura do 
arquivo"); 
 exit (1); 
 } 
do 
 { printf("\n\nDigite o titulo: "); 
 gets(livro.titulo); 
 printf("Digite o registro: "); 
 gets(numstr); 
 livro.regnum=atoi(numstr); 
 printf("Digite o preco: "); 
 gets(numstr); 
 livro.preco=atof(numstr); 
 fwrite(&livro, sizeof(livro), 1, fptr); 
 printf("Adicionar outro livro(s/n) ?"); 
 } while (getche() == 's'); 
 fclose(fptr); 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
fwrite(&livro, sizeof(livro), 1, fptr) 
ponteiro para o local da memória 
onde os dados lidos ficarão armaz. 
quantidade de bytes a serem lidos 
quantid de itens a serem lidos 
a cada chamada 
ponteiro para FILE 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
93 
 
Exemplo de leitura de 01 bloco de dados: 
 
#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ struct 
 { char titulo[30]; 
 int regnum; 
 double preco; 
 } livro; 
 FILE * fptr; 
 
 fptr=fopen("livros.rec","rb"); 
if (fptr == NULL) 
{ printf("\nErro na abertura do arquivo 
livros.rec"); 
 exit (1); 
} 
while (fread &livro, sizeof(livro), 1, fptr)==1) 
{ printf("\nTitulo: %s",livro.titulo); 
 printf("\nRegistro: 3d",livro.regnum); 
 printf("\nPreco: %.2f\n",livro.preco); 
} 
fclose(fptr); 
return 0; 
} 
 
 
 
 
13.3.8 Teste para identificar a criação ou abertura de um arquivo 
 
Não é usual termos um programa para criar (abrir pela primeira vez) e outro para 
abrir sempre que precisarmos fazer manutenção no arquivo (acresentar dados, 
pesquisar, excluir, alterar etc.). 
Torna-se então necessário implementar um teste que faça o compilador avaliar a 
situação do arquivo (ele já existe?). 
Abaixo mostra-se uma solução possível, testando o retorno da abertura de arquivo 
existente: 
 
int main() 
{ FILE *arq; 
 char nomearq[25]; 
 printw("informe o nome do arquivo\n"); 
 scanw("%s", nomearq); 
 arq=fopen(nomearq,"rb+"); //abre para leitura ou gravação 
 if(arq==NULL) 
 { arq=fopen( nomearq,"wb+"); //cria para leitura ou gravação 
 if(arq==NULL) 
 { printw(" O arquivo não pode ser aberto"); 
 exit(1); 
 } 
 else 
 { printw("arquivo aberto com sucesso! (tecle enter)"); 
 getch(); 
 } 
 return 0; 
 } 
fread(&livro, sizeof(livro), 1, fptr) == 1 
ponteiro para o local da memória 
onde os dados lidos ficarão armaz. 
quantidade de bytes a serem lidos 
quantid de itens a serem lidos a cada chamada 
ponteiro para FILE 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
94 
 
 13.4.9 exemplo de uma função para devolver o tamanho de um arquivo 
// função criada para informar o tamanho de um arquivo 
long calcularTamanhoArquivo(FILE *arquivo) 
{ // guarda o estado antes de chamar a função fseek 
 long posicaoAtual = ftell(arquivo); 
 // guarda tamanho do arquivo 
 long tamanho; 
 // calcula o tamanho 
 fseek(arquivo, 0, SEEK_END); 
 tamanho = ftell(arquivo); 
 // recupera o estado antigo do arquivo 
 fseek(arquivo, posicaoAtual, SEEK_SET); 
 return tamanho; 
} 
 
 
 
14.0 Estruturas e alocação dinâmica de memória – exemplo com 
Lista Encadeada 
 
 Uma lista encadeada é um conjunto de itens (células, nodos), onde cada 
elemento contém uma informação e um ponteiro para o próximo item. 
 Possui também um ponteiro para o seu início e o ponteiro do último elemento 
tem o valor NULL. 
 Para colocar um novo item , basta criar uma nova célula, apontar o campo 
prox da célula anterior para a nova célula, ler os dados e fazer o seu campo 
prox igual a NULL. 
 Para percorrer a lista inicia-se pelo endereço apontado pela celula cabeça e 
segue-se o “caminho” definido pelos endereços dos campos prox de cada 
item. 
 
 
 
 
Supondo que os objetos armazenados nas células são do tipo int, a estrutura de 
cada célula da lista pode ser definida assim: 
 
 
 
 struct cel { 
 int conteudo; 
 struct cel *prox; 
 }; 
 
 
 
 
 
 
conteudo prox 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
95 
 
14.1 Comando typedef 
 
O comando typedef permite ao programador definir um novo nome para um deter-
minado tipo. Sua forma geral é: 
 typedef antigo_nome novo_nome; 
 
É conveniente tratar as células como um novo tipo de dados e atribuir um nome a 
esse novo tipo: 
 typedef struct cel celula; 
 
Após a designação typedef, uma célula c e um ponteiro p para uma célula po-
dem ser declarados assim: 
 celula c; 
 celula *p; 
 
Outro exemplo: 
 
#include <stdio.h> 
typedef struct tipo_endereco 
 { 
 char rua [50]; 
 int numero; 
 char bairro [20]; 
 char cidade [30]; 
 char sigla_estado [3]; 
 long int CEP; 
 } TEndereco; 
 
typedef struct ficha_pessoal 
 { 
 char nome [50]; 
 long int telefone;TEndereco endereco; 
 }TFicha; 
 
int main() 
{ 
TFicha *ex; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
96 
 
14.2 Lista Encadeada 
 
 
 
 
 
Declaração de ponteiro para a estrutura: 
 
 
 
struct nodo *prim; 
 
 
No momento em que o programa precisa de espaço na mémória para um nodo ele 
o aloca: 
 
prim=(struct nodo*)malloc(sizeof(struct nodo)) 
 
 
 
A seguir, é possível armazenar valores no nodo: 
 
 
prim.info = 5; 
prim.prox = NULL; 
 
 
 
Para criar uma lista encadeada, com inserção no final, necessitamos um nú-
mero maior de ponteiros: 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
97 
 
 
 
 
struct nodo 
{ int info; 
 struct nodo *prox; 
}; 
struct nodo *prim, *novo,*atual; 
 
• prim permanecerá apontando o pri-
meiro 
• novo será usado sempre para alo-
car novo espaço 
• atual fará o campo prox apontar 
para o novo espaço 
• depois atual assumirá o endereço 
de novo, e permitirá entrar com info 
e fazer prox apontar para null 
 
 
 
#include <stdio.h> 
#include <stdlib.h> 
typedef struct nodo /* Estrutura que será usada para criar 
os nodos da lista */ 
{ int info; 
 struct nodo *prox; //ponteiro para próximo elem. da lista 
} Tnodo; 
 
void inserir(Tnodo **cabeca); /* Protótipos das funcoes para in-
serir e listar elementos da lista */ 
void listar (Tnodo *cabeca); 
 
int main() 
{ Tnodo *cabeca = NULL; /* Ponteiro para a cabeça da lista */ 
 Tnodo *noatual; /* Ponteiro para percorrer a 
lista no momento de desalocar seus ele-
mentos*/ 
 char q; /* Caractere para receber a opção do usuario*/ 
 do { 
 printf("\n\nOpcoes: \nI - inserir novo nodo \nl – listar 
todos os nodos \nS - sair \nInforme sua opcao: "); 
 scanf("%c", &q); // Le a opcao do usuario 
 switch(q) { 
 case 'i': case 'I': inserir(&cabeca); 
 break; 
 case 'l': case 'L': listar(cabeca); 
 break; 
 case 's': case 'S': break; 
 default: printf("\n\n Opcao nao valida"); 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
98 
 
 } 
 getchar(); 
 while ((q != 's') && (q != 'S') ); 
 noatual = cabeca; 
 while (noatual != NULL) 
 { cabeca = noatual->prox; 
 free(noatual); /* Desaloca a memoria alocada para os 
elementos da lista*/ 
 noatual = cabeca; 
 } 
 return 0; 
} 
 
 
void listar (Tnodo *noatual) /* Lista todos os nodos presentes na 
lista encadeada*/ 
{ int i=0; 
 while( noatual != NULL) /*Enquanto nao atinge o fim da lista*/ 
 { i++; 
 printf("\n Informacao %d = %d ", i, noatual->info); 
 noatual = noatual->prox; /* Faz noatual apontar para o 
proximo nodo*/ 
 } 
} 
 
void inserir (Tnodo **cabeca) /* Funcao para inserir um novo nodo, 
ao final da lista */ 
{ Tnodo *noatual, *novono; 
 int cod; 
 printf("\n Informacao: "); 
 scanf("%d", &cod); 
 if (*cabeca == NULL) /* Se ainda nao existe nenhum produto na 
lista*/ 
 { *cabeca = malloc(sizeof(Tnodo)); // cria o nodo cabeca 
 (*cabeca)->info = cod; 
 (*cabeca)->prox = NULL; 
 } 
 else 
 { noatual = *cabeca; /* Se ja existem elementos na lista, 
deve percorre-la ate o seu final e inserir o 
novo elemento */ 
 while(noatual->prox != NULL) 
 noatual = noatual->prox; /* Ao final do while, noatual 
aponta p/ o último nodo */ 
novono = malloc(sizeof(Tnodo)); /* Aloca memoria para o 
novo nodo*/ 
 novono->info = cod; 
 novono->prox = NULL; 
 noatual->prox = novono; /* Faz o último nodo apontar 
para o novo nodo*/ 
 } 
} 
 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
99 
 
15.00 Como criar um arquivo “header” em C no Code::Blocks v13.12 
 
A partir de um projeto já iniciado, que no exemplo (figura 1) é chamado de teste_he-
ader: 
 
 
Figura 1 
 
1- Entre no menu File – New – File (figura 2): 
 
Figura 2 
 
2- Escolha C/C++ Header – Go (figura 3): 
 
Figura 3 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
100 
 
3- O próximo passo é dar um nome definindo também o diretório para salvar o 
arquivo (figura 4): 
 
Figura 4 
 
4- Aperte Finish e sua tela deverá estar como mostra a figura 5: 
 
Figura 5 
 
 
5- Para finalizar, implemente as funções da biblioteca: 
 
Figura 6 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
101 
 
16. 0 Tabela ASCII 
 
As tabelas mostradas neste anexo representam os 256 códigos usados nos computa-
dores da família IBM. Esta tabela refere-se ao American Standard Code for Information 
Interchange (código padrão americano para troca de informações), que é um conjunto 
de números representando caracteres ou instruções de controle usados para troca de 
informações entre computadores entre si, entre periféricos (teclado, monitor, impres-
sora) e outros dispositivos. Estes códigos tem tamanho de 1 byte com valores de 00h 
a FFh (0 a 255 decimal). Podemos dividir estes códigos em três conjuntos: controle, 
padrão e estendido. 
 
Os primeiros 32 códigos de 00h até 1Fh (0 a 31 decimal), formam o conjunto de con-
trole ASCII. Estes códigos são usados para controlar dispositivos, por exemplo uma 
impressora ou o monitor de vídeo. O código 0Ch (form feed) recebido por ima impres-
sora gera um avanço de uma página. O código 0Dh (carriage return) é enviado pelo 
teclado quando a tecla ENTER é pressionada. Embora exista um padrão, alguns pou-
cos dispositivos tratam diferentemente estes códigos e é necessário consultar o manual 
para saber exatamente como o equipamento lida com o código. Em alguns casos o 
código também pode representar um caracter imprimível. Por exemplo o código 01h 
representa o caracter  (happy face). 
 
 Os 96 códigos seguintes de 20h a 7Fh (32 a 127 decimal) formam o conjunto padrão 
ASCII. Todos os computadores lidam da mesma forma com estes códigos. Eles repre-
sentam os caracteres usados na manipulação de textos: códigos-fonte, documentos, 
mensagens de correio eletrônico, etc. São constituídos das letras do alfabeto latino (mi-
núsculo e maiúsculo) e alguns símbolos usuais. 
 
Os restantes 128 códigos de 80h até FFh (128 a 255 decimal) formam o conjunto 
estendido ASCII. Estes códigos também representam caracteres imprimíveis porem 
cada fabricante decide como e quais símbolos usar. Nesta parte do código estão defi-
nidas os caracteres especiais: é, ç, ã, ü ... 
 
 
 
Dec. Hex. Controle 
0 00h NUL (Null) 
1 01h SOH (Start of Heading) 
2 02h STX (Start of Text) 
3 03h ETX (End of Text) 
4 04h EOT (End of Transmision) 
5 05h ENQ (Enquiry) 
6 06h ACK (Acknowledge) 
7 07h BEL (Bell) 
8 08h BS (Backspace) 
9 09h HT (Horizontal Tab) 
10 0Ah LF (Line Feed) 
11 0Bh VT (Vertical Tab) 
12 0Ch FF (Form Feed) 
13 0Dh CR (Carriage Return) 
14 0Eh SO (Shift Out) 
15 0Fh SI (Shift In) 
16 10h DLE (Data Link Escape) 
17 11h DC1 (Device control 1) 
18 12h DC2 (Device control 2) 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
102 
 
19 13h DC3 (Device control 3) 
20 14h DC4 (Device control 4) 
21 15h NAK (Negative Acknowledge)22 16h SYN (Synchronous Idle) 
23 17h ETB (End Transmission Block) 
24 18h CAN (Cancel) 
25 19h EM (End of Media) 
26 1Ah SUB (Substitute) 
27 1Bh ESC (Escape) 
28 1Ch FS (File Separator) 
29 1Dh GS (Group Separator) 
30 1Eh RS (Record Separator) 
31 1Fh US (Unit Separator) 
 
 
 
 
 
 
Caracter Dec. Hex. 
<espaço> 32 20h 
! 33 21h 
" 34 22h 
# 35 23h 
$ 36 24h 
% 37 25h 
& 38 26h 
' 39 27h 
( 40 28h 
) 41 29h 
* 42 2Ah 
+ 43 2Bh 
, 44 2Ch 
- 45 2Dh 
. 46 2Eh 
/ 47 2Fh 
0 48 30h 
1 49 31h 
2 50 32h 
3 51 33h 
4 52 34h 
5 53 35h 
6 54 36h 
7 55 37h 
8 56 38h 
9 57 39h 
: 58 3Ah 
; 59 3Bh 
< 60 3Ch 
= 61 3Dh 
> 62 3Eh 
? 63 3Fh 
@ 64 40h 
A 65 41h 
B 66 42h 
C 67 43h 
Caracter Dec. Hex. 
D 68 44h 
E 69 45h 
F 70 46h 
G 71 47h 
H 72 48h 
I 73 49h 
J 74 4Ah 
K 75 4Bh 
L 76 4Ch 
M 77 4Dh 
N 78 4Eh 
O 79 4Fh 
P 80 50h 
Q 81 51h 
R 82 52h 
S 83 53h 
T 84 54h 
U 85 55h 
V 86 56h 
W 87 57h 
X 88 58h 
Y 89 59h 
Z 90 5Ah 
[ 91 5Bh 
\ 92 5Ch 
] 93 5Dh 
^ 94 5Eh 
_ 95 5Fh 
` 96 60h 
a 97 61h 
b 98 62h 
c 99 63h 
d 100 64h 
e 101 65h 
f 102 66h 
g 103 67h 
Caracter Dec. Hex. 
h 104 68h 
i 105 69h 
j 106 6Ah 
k 107 6Bh 
l 108 6Ch 
m 109 6Dh 
n 110 6Eh 
o 111 6Fh 
p 112 70h 
q 113 71h 
r 114 72h 
s 115 73h 
t 116 74h 
u 117 75h 
v 118 76h 
w 119 77h 
x 120 78h 
y 121 79h 
z 122 7Ah 
{ 123 7Bh 
| 124 7Ch 
} 125 7Dh 
~ 126 7Eh 
<delete> 127 7Fh 
Ç 128 80h 
ü 129 81h 
é 130 82h 
â 131 83h 
ä 132 84h 
à 133 85h 
å 134 86h 
ç 135 87h 
ê 136 88h 
ë 137 89h 
è 138 8Ah 
ï 139 8Bh 
Caracter Dec. Hex. 
î 140 8Ch 
ì 141 8Dh 
Ä 142 8Eh 
Å 143 8Fh 
É 144 90h 
Æ 145 91h 
Æ 146 92h 
ô 147 93h 
ö 148 94h 
ò 149 95h 
û 150 96h 
ù 151 97h 
ÿ 152 98h 
Ö 153 99h 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
104 
 
Ü 154 9Ah 
¢ 155 9Bh 
£ 156 9Ch 
¥ 157 9Dh 
₧ 158 9Eh 
ƒ 159 9Fh 
ááááá 160 A0h 
í 161 A1h 
ó 162 A2h 
ú 163 A3h 
ñ 164 A4h 
Ñ 165 A5h 
ª 166 A6h 
º 167 A7h 
¿ 168 A8h 
⌐ 169 A9h 
¬ 170 AAh 
½ 171 ABh 
¼ 172 ACh 
¡ 173 ADh 
« 174 AEh 
» 175 AFh 
░ 176 B0h 
Caracter Dec. Hex. 
▒ 177 B1h 
▓ 178 B2h 
│ 179 B3h 
┤ 180 B4h 
╡ 181 B5h 
╢ 182 B6h 
╖ 183 B7h 
╕ 184 B8h 
╣ 185 B9h 
║ 186 BAh 
╗ 187 BBh 
╝ 188 BCh 
╜ 189 BDh 
╛ 190 BEh 
┐ 191 BFh 
└ 192 C0h 
┴ 193 C1h 
┬ 194 C2h 
├ 195 C3h 
─ 196 C4h 
┼ 197 C5h 
╞ 198 C6h 
╟ 199 C7h 
╚ 200 C8h 
╔ 201 C9h 
╩ 202 CAh 
╦ 203 CBh 
 204 CCh 
═ 205 CDh 
╬ 206 CEh 
╧ 207 CFh 
╨ 208 DOh 
╤ 209 D1h 
╥ 210 D2h 
╙ 211 D3h 
╘ 212 D4h 
╒ 213 D5h 
Caracter Dec. Hex. 
╓ 214 D6h 
╫ 215 D7h 
╪ 216 D8h 
┘ 217 D9h 
┌ 218 DAh 
█ 219 DBh 
▄ 220 DCh 
▌ 221 DDh 
▐ 222 DEh 
▀ 223 DFh 
Α 224 E0h 
ß 225 E1h 
Γ 226 E2h 
π 227 E3h 
Σ 228 E4h 
σ 229 E5h 
µ 230 E6h 
Τ 231 E7h 
Φ 232 E8h 
Θ 233 E9h 
Ω 234 EAh 
δ 235 EBh 
∞ 236 ECh 
φ 237 EDh 
 238 EEh 
∩ 239 EFh 
≡ 240 F0h 
± 241 F1h 
≥ 242 F2h 
≤ 243 F3h 
⌠ 244 F4h 
⌡ 245 F5h 
÷ 246 F6h 
≈ 247 F7h 
° 248 F8h 
∙ 249 F9h 
· 250 FAh 
Caracter Dec. Hex. 
√ 251 FBh 
ⁿ 252 FCh 
² 253 FDh 
· 254 FEh 
 255 FFh 
 
 
Notas de aula de Programação Estruturada 
Professoes Beatriz Lux e Rolf F. Molz 
 
105 
 
Entre os caracteres da tabela ASCII estendidos, os mais úteis são, talvez, os caracteres 
de desenho de quadro em linhas simples e duplas: os caracteres de B3h até DAh (179 a 
218 decimal). Como a visualização deste conjunto é difícil, o desenho abaixo pode auxiliar 
nesta tarefa: 
 
 196 194 205 203 
218 ┌ ─ ┬ ┐ 191 201 ╔ ═ ╦ ╗ 187 
179 │ 186 ║ 
195 ├ ┼ ┤ 180 204 ╠ ╬ ╣ 185 
 197 206 
192 └ ┴ ┘ 217 200 ╚ ╩ ╝ 188 
 193 202 
 209 210 
213 ╒ ╤ ╕ 184 214 ╓ ╥ ╖ 183 
198 ╞ ╪ ╡ 181 199 ╟ ╫ ╢ 182 
 216 215 
212 ╘ ╧ ╛ 190 211 ╙ ╨ ╜ 189 
 207 208 
 
Material retirado de: 
 http://cpd-srv03.unifra.br/~walkiria/alg_prog2/exe-nteriores/tabela%20ASCII.doc

Mais conteúdos dessa disciplina