Академический Документы
Профессиональный Документы
Культура Документы
Espírito Santo
PROGRAMAÇÃO I
Vila Velha / ES
2008
1
1 - Introdução
O raciocínio lógico é usado por todos na solução de diversos problemas cotidianos. Especialmente pelos
profissionais de informática, pois seu dia-a-dia profissional consiste em solucionar problemas e atingir os
objetivos apresentados pelos usuários, utilizando os recursos computacionais disponíveis com eficiência
e eficácia.
Esta disciplina não pretende ensinar ninguém a pensar de forma lógica. Todos nós temos este dom.
Nosso objetivo é, através de técnicas de programação, aperfeiçoar o uso do raciocínio lógico no
desenvolvimento de programas de computador, lembrando que isso exigirá persistência e prática
constante, chegando à exaustão sempre que necessário.
Utilizamos algoritmos quotidianamente, por exemplo, quando seguimos uma receita de omelete:
Pegue uma tigela pequena.
Acrescente 3 ovos sem casca
Acrescente uma colher de café de sal
Mexa durante 2 minutos
Frite em óleo quente
ALGORITMO é uma seqüência finita de passos que ao serem executados visam tingir um objetivo bem definido.
Como exemplo, construiremos um algoritmo para cálculo da média de duas notas de 0 a 10,
fornecidas pelo usuário:
O computador não possui experiências anteriores, nem poder de discernimento e raciocínio. Temos que
fornecer ao computador detalhes de todas as ações que ele deve executar, prevendo todos os
obstáculos e a forma de transpô-los. Ou seja, temos que definir uma seqüência finita de passos que
garantam a solução do problema.
Primeira Solução:
Digite a primeira nota
Digite a segunda nota
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
Involuntariamente seguimos uma determinada seqüência de ações para representar nosso algoritmo,
calculando a média. Mas se o usuário fornecer uma nota inválida (menor que zero ou maior que 10)?
Para solucionar este problema, antes de calcular a média devemos verificar se as notas são válidas.
Segunda Solução:
Digite a primeira nota
Digite a segunda nota
SE as notas forem válidas
inicio
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
fim
Agora estamos ligando algumas ações à condição das notas serem válidas. Observe a inclusão de um
TESTE SELETIVO que determina quais ações serão executadas (note que antes todas eram).
Vamos melhorar a interface do nosso programa. Caso as notas não sejam válidas mostraremos uma
mensagem de erro.
Terceira Solução:
Digite a primeira nota
Digite a segunda nota
SE as notas forem válidas
inicio
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
fim
SENÃO
inicio
Mostre na tela a mensagem “valores inválidos digitados para uma ou mais notas.”
fim
Mudemos um pouco o problema, ainda calcularemos a média de duas notas lidas, porém repetiremos a
leitura até que o usuário forneça duas notas válidas. Quando então calcularemos a média. É impossível
definir quantas digitações serão necessárias até que o usuário forneça duas notas válidas. Assim
repetiremos a leitura até a correta digitação.
Quarta Solução:
ENQUANTO notas inválidas
inicio
Digite a primeira nota
Digite a segunda nota
SE notas inválidas
inicio
Mostre na tela a mensagem “valores inválidos digitados para uma ou mais notas.”
fim
fim
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
Nem sempre o primeiro algoritmo proposto representa a melhor solução para o problema. Às
vezes é necessário torná-lo mais eficiente. Observando o exemplo vemos que ele pode ser
aperfeiçoado, podemos testar cada nota em separado.
Quinta Solução:
ENQUANTO primeira nota inválida
inicio
Digite a primeira nota
SE primeira nota inválida
inicio
Mostre na tela a mensagem “valor inválido digitado para a primeira nota.”
fim
fim
ENQUANTO segunda nota inválida
inicio
Digite a segunda nota
SE segunda nota inválida
inicio
Mostre na tela a mensagem “valor inválido digitado para a segunda nota.”
fim
fim
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
A condição nota inválida estabeleceu um FLUXO REPETITIVO que será finalizado assim que a condição
for falsa, ou seja, que uma nota válida for digitada.
Até agora estamos efetuando o cálculo da média de um aluno. Imagine se tivermos que calcular a média
de 10 alunos? Uma solução seria repetir o bloco de comandos acima 10 vezes. Poderíamos, entretanto,
fazer com que após o cálculo de uma média o fluxo de execução retornasse e executasse novamente o
cálculo para duas novas notas. Gerando um FLUXO REPETITIVO por 10 vezes.
Sexta Solução:
PARA 10 alunos { número de repetições definido }
inicio
ENQUANTO primeira nota inválida { número de repetições indefinido }
inicio
Digite a primeira nota
SE primeira nota inválida { teste condicional }
inicio
Mostre na tela a mensagem “valor inválido digitado para a primeira nota.”
fim
fim
ENQUANTO segunda nota inválida
inicio
Digite a segunda nota
SE segunda nota inválida
inicio
Mostre na tela a mensagem “valor inválido digitado para a segunda nota.”
fim
fim
Some as notas digitadas
Divida a soma por 2
Mostre o resultado na tela
fim
Quando escrevemos a solução de um problema utilizando uma linguagem de programação estamos construindo um
PROGRAMA.
2 - Histórico da Linguagem C
Optamos por trabalhar com a Linguagem de Programação C. Ela tem sido amplamente utilizada na
elaboração de programas e sistemas nas áreas em que a informática atua, e seu aprendizado tornou-se
indispensável para quem trabalha com programação de computadores.
A linguagem C foi criada por Dennis Ritchie, em 1972, no centro de Pesquisas da Bell Laboratories. Sua
primeira utilização importante foi a reescrita do Sistema Operacional UNIX, que até então era escrito em
assembly.
Em meados de 1970 o UNIX saiu do laboratório para ser liberado para as universidades. Foi o suficiente
para que o sucesso da linguagem atingisse proporções tais que, por volta de 1980, já existiam várias
versões de compiladores C oferecidas por várias empresas, não sendo mais restritas apenas ao
ambiente UNIX, porém compatíveis com vários outros sistemas operacionais.
3 – Conceitos Fundamentais
Existem diversos tipos de computadores. Embora não seja nosso objetivo estudar hardware, nesta seção
identificaremos os elementos essenciais de um computador. O conhecimento desses elementos nos
ajudará a compreender como um programa de computador funciona. A figura abaixo identifica os
elementos básicos de um computador típico:
Canal de comunicação - BUS
Memória Memória
CPU principal secundária
Dispositivos de
Entrada/Saída
- Canal de Comunicação (BUS): representa o meio de transferência de dados entre os diversos componentes.
- Unidade Central de Processamento (CPU): representa o “cérebro” do computador, e é responsável pelo controle de todas
as operações realizadas.
- Memória Principal: para que a CPU possa executar uma seqüência de comandos ou acessar uma determinada informação,
é necessário armazenar os comandos e os dados correspondentes na memória principal. A memória principal tem
acesso randômico, o que significa que a CPU pode endereçar (acessar) diretamente qualquer posição na memória. Essa
memória não é permanente e, para um programa, os dados são armazenados enquanto ele está sendo executado.
Normalmente, após o término do programa, a área correspondente ocupada na memória fica disponível para ser usada por
outros programas.
- Área de Armazenamento Secundário: Essa memória tem a vantagem de ser permanente, os dados armazenados em
disco permanecem válidos mesmo depois de encerrado os programas. Ela tem custo mais baixo do que a memória principal,
porém o acesso as dados é bem mais lento. Para que a CPU processe um dado armazenado na memória secundária, é
necessário que antes ele seja transferido para a memória principal.
- Dispositivos de Entrada e Saída: os dispositivos de entrada (por exemplo, teclado e mouse) permitem passar dados para
um programa, enquanto os dispositivos de saída permitem que um programa exporte seus resultados (por exemplo, monitor e
impressora).
Nada além de zeros e uns pode ser armazenado na memória do computador. Por essa razão, todas as
informações (programas, textos, imagens, etc.) são armazenadas com o uso de uma codificação
numérica na forma binária (seqüência de oito zeros e uns). Por exemplo, o número 5 é representado na
base binária com a seqüência 00000101.
Editor
Programa Programa
Compilador
Fonte Objeto
Programa
Ligador
Executável
Bibliotecas
incluídas
O programa executável, por ser escrito em Linguagem de Máquina, pode ser executado em qualquer
máquina que possua a mesma Linguagem de Máquina. A máquina em que o programa é executado não
precisa ter um Compilador instalado, nem precisa ter acesso ao código C do programa.
4- Estrutura de um Programa em C
system("PAUSE"); //exibe a mensagem ”Pressione qualquer tecla para continuar...” e aguarda que algo seja teclado
}
Observações:
i - Função main
Um programa em C deve ter obrigatoriamente a função principal main, uma vez que a execução do
programa começa sempre por ela.
A execução se inicia na primeira instrução da função main e continua executando seqüencialmente até a
última instrução, obedecendo a ordem em que elas são dispostas no texto da main.
Por enquanto utilizaremos o cabeçalho da função main em sua forma mais simples, como a mostrada no
exemplo. Posteriormente retornaremos a este assunto para mais detalhes.
ii - Bibliotecas
As bibliotecas são incluídas no programa através do comando #include. No nosso exemplo, a biblioteca
<stdio.h> se fez necessária devido aos comandos printf e scanf. A biblioteca <stdlib.h> se deve ao
comando system. O compilador ao encontrar uma instrução #include no programa fonte traduzirá o texto
presente no arquivo *.h da instrução #include da mesma forma como faria se o texto tivesse sido digitado
no programa fonte.
iii - Chaves
Os símbolos { e } indicam início e fim de uma rotina.
v - Ponto-e-vírgula
O ponto-e-vírgula é usado para terminar as declarações e comandos.
vi - Comentários:
Os comentários, utilizado para documentação do programa e ignorados durante a compilação, podem
ser incluídos no código fonte utilizando: // para comentários de linha ou /* */ para bloco de comentários.
ix - Identificadores
São nomes usados para se fazer referência a variáveis, constantes, tipos, funções, e vários outros
objetos definidos pelo usuário. Podem ser escritos usando letras, dígitos e sublinhado. Sendo que o
primeiro caractere deve ser uma letra ou um sublinhado.
Cada identificador deve identificar um único objeto dentro de um mesmo escopo do programa e deve ser
representativo quanto a sua função no programa.
A forma de escrita de um identificador é de fundamental importância para a qualidade e extencibilidade
do programa. Atualmente desenvolvedores do mundo todo tem usado os padrões de nomes sugeridos
pela Microsoft, sendo eles:
Pascal Case:
A primeira letra do identificador e a primeira letra de cada palavra subseqüente concatenada é escrita em
maiúscula.
Exemplos: SalarioFamilia, DataAniv
Camel Case:
A primeira letra do identificador é escrita em minúscula e a primeira letra de cada palavra subseqüente
concatenada é escrita em maiúscula.
Exemplos: salarioFamilia, dataAniv
Uppercase:
Todas as letras do identificador são escritas em maiúscula. Este padrão deve ser usado apenas para
identificadores compostos por duas ou menos letras.
Exemplos: ID
Para armazenar um dado (valor) na memória do computador devemos reservar o espaço (em bytes)
correspondente ao tipo do dado. A linguagem C possui diversos tipos básicos de dados, nós
trabalharemos com os listados abaixo, observe que cada um utiliza um espaço de memória (número de
bytes) diferente.
O tipo lógico (falso ou verdadeiro) não existe na linguagem C. Um valor igual a zero é considerado um
valor lógico falso, e qualquer valor diferente de zero (por exemplo, 1) é considerado um valor lógico
verdadeiro. Mais tarde usaremos este fato nas condições das estruturas de controle.
6 - Variáveis
Quando desenvolvemos um programa este normalmente recebe dados, os quais precisam ser
armazenados na memória RAM do computador para que possam ser usados no processamento. As
variáveis são usadas para permitir o armazenamento e o processamento destes dados.
Variável, no sentido de programação, é uma região previamente identificada e que tem por finalidade
armazenar temporariamente os dados de um programa.
O tipo do dado do valor armazenado deve ser definido previamente, uma vez que, cada tipo de dado é
armazenado de forma diferente na memória, gastando quantidades diferentes de bytes.
Sintaxe:
<tipo de dado> <nome da variável>;
onde:
<tipo de dado> - determina a natureza do dado que será armazenado.
<nome da variável> - serve de referência ao dado armazenado no espaço de memória
Quando duas ou mais variáveis forem do mesmo tipo, estas podem ser declaradas juntas, basta separá-
las por vírgula.
Exemplos:
int num;
float nota1, nota2;
char sexo;
Um valor pode ser atribuído a uma posição de memória representada por uma variável através do
operador de atribuição =. O operador de atribuição, em geral, possui à esquerda um nome de variável e
à direita um valor.
Uma vez declarada a variável só podemos lhe atribuir valores do mesmo tipo declarado, ou menores.
Não é possível, por exemplo, armazenar um valor real em uma variável inteira. Se fizermos:
int x;
x = 4.3;
será armazenado em x apenas a parte inteira do número real, isto é, 4. Alguns compiladores exibem
uma advertência quando encontram este tipo de atribuição. Uma exceção permitida é a atribuição de um
valor inteiro a uma variável float ou double, neste caso o valor inteiro é automaticamente convertido para
float ou double.
7 - Constantes
Declaramos como constantes dados que permanecerão inalterados durante toda a execução do
programa. As constantes são usadas muitas vezes para aumentar a clareza, a facilidade de manutenção
e a legibilidade do programa.
Sintaxe:
#define <nome da constante> <valor>
Exemplo:
#define Media 7
8 - Operadores
As operações são feitas no tipo do operando de maior precisão. Assim, se somarmos um número int a
um número double, teremos um resultado double.
Particularmente, na divisão a expressão 5/2 resulta no valor 2, já que a operação / é feita na precisão
inteira, uma vez que 5 e 2 são inteiros. Já as expressões 5.0/2.0, 5/2.0 ou 5.0/2 resultam no valor real
2.5, uma vez que pelo menos um dos operandos é real.
Operadores com a mesma ordem de prioridade são avaliados da esquerda para a direita, ou seja, o
operador que aparece primeiro. Assim, na expressão
a+b*c/d
executa-se 1º a multiplicação, seguida da divisão e da soma. A Ordem de Prioridade pode ser alterada
através dos parênteses. Assim, na expressão
(a + b) * c / d
executa-se primeiro a soma seguida da multiplicação e divisão.
A linguagem C, como usado anteriormente, utiliza o símbolo = para atribuir valores a variáveis. Por
exemplo, x = 5, armazena o valor 5 no espaço de memória reservado para a variável x.
È possível atribuir valores a mais de uma variável ao mesmo tempo. Neste caso a ordem de avaliação é
da direita para a esquerda. No exemplo,
y = x = 5;
o computador avalia x = 5, armazenando 5 em x, e, em seguida, armazena em y o valor produzido por x
= 5, que é 5. Portanto, x e y recebem o valor 5.
Uma operação muito comum em programação e o incremento ou decremento de uma unidade no valor
de uma variável. A linguagem C traz dois operadores, ++ e --, para facilitar estas operações.
Exemplo:
int x = 5;
x++; // resulta em x=6
x = 5;
++x; // resulta em x=6
Contudo, quando a operação de incremento ou decremento faz parte de uma expressão faz muita
diferença usar o operador como prefixo ou sufixo.
Exemplo:
int y;
int x = 5;
y = x++ + 2; // equivalente a y = x + 2; seguido de x = x + 1; resulta em y = 7 (5+2) e x = 6
x = 5;
y = ++x + 2; // equivalente a x = x + 1; seguido de y = x + 2; resulta em x = 6 e y = 8 (6+2)
A prioridade dos operadores segue a precedência posicional, ou seja, o operador que primeiro aparece
na expressão tem maior prioridade. Os parênteses podem ser usados para alterar a prioridade.
Exemplo:
Supondo A = 10 e B = 5, temos:
A>B não retorna 0 - verdadeiro
(A = = B) != (5 < B) retorna 0 - falso
Expressões conectadas por !, &&, ou || são avaliadas da esquerda para a direita, e a avalição pára
assim que a veracidade ou a falsidade do resultado for conhecida. O resultado obtido será sempre um
valor 0 (falso) ou diferente de zero (verdadeiro). Os parênteses podem ser usados para mudar a
prioridade das operações.
Como os operadores aritméticos, relacionais e lógicos podem ser combinados dentro de uma mesma
expressão a prioridade entre eles deve ser observada. Os parênteses podem ser usados para mudança
na prioridade.
Prioridade Operador
1 !
2 *, /, %, &&
3 +, -, ||
4 = = , !=, >, <, >=, <=
Observe que !b não chega a ser avaliada, pois, independente do seu resultado a expressão terá como resultado verdadeiro, uma
vez que !(x < y + 2) tem valor verdadeiro.
Transmite para o mundo exterior (dispositivo de saída - adotaremos o monitor como dispositivo de saída
padrão) um ou mais valores, permitindo ao usuário acesso aos resultados obtidos pelo algoritmo.
Sintaxe:
printf (<formatos>, <lista de constantes/variáveis/expressões>);
Onde <formatos> é uma cadeia de caracteres, delimitada por aspas, que contém o formato de saída das
constantes, variáveis e expressões listadas a seguir.
Na <lista de constantes/variáveis/expressões>, para cada valor que se deseja imprimir, deve existir
ordenadamente um especificador de formato correspondente na cadeia de caracteres <formatos>. Os
diversos valores devem ser separados por vírgula.
Os especificadores de formato (ou tags) variam com o tipo do valor e a precisão com que queremos que
sejam impressos. Estes especificadores são precedidos pelo caracter % e podem ser, entre outros:
Especificador ou Tag Significado
%c Especifica um char
%d Especifica um int
%f Especifica um double ou float
%e Especifica um double ou float no formato científico
%s Especifica uma cadeia de caracteres
%7.2f – especifica a impressão de um double ou float usando no mínimo 7 caracteres, fixando 2 casas decimais. Espaços em
branco por ventura existentes são alinhados à esquerda.
Se o tamanho do campo for maior do que o necessário para a impressão são incluídos caracteres brancos à esquerda. Se o
tamanho do campo for menor que o necessário para a impressão este é ignorado e o número é impresso normalmente.
Exemplo:
Comando Valor Impresso
float x = 21.5687124; printf("%5f", x); 21.568712
printf("%7.2f", x); 21.57
printf("%5.2f", x); 21.57
printf("%.3f", x); 21.569
Existem ainda outros caracteres de escape freqüentemente usados nos formatos de saída. Entre eles:
Caracter de Escape Significado
\n Imprime uma nova linha
\t Imprime uma tabulação horizontal
\” Imprime o caracter “
\\ Imprime o caracter \
Exemplos:
printf (“Salário Mensal: R$ %7.2f \n”, salarioFunc);
printf (“Média: %5.2f Total de Faltas: %d, (nota1 + nota2)/2, faltas);
Transfere um ou mais dados do mundo exterior (dispositivo de entrada - adotaremos o teclado como
dispositivo de entrada padrão) para uma ou mais variáveis na memória.
Como no comando de atribuição o valor transferido para a variável deve ser compatível com o tipo para
ela declarado.
Sintaxe:
scanf (<formatos>, <lista de endereços das variáveis>);
Onde <formatos> possuem especificadores similares aos usados pela função printf. Exceção para os
tipos float e double que possuem especificadores distintos.
Especificador Significado
%c Especifica um char
%d Especifica um int
%f Especifica um float
%lf Especifica um doble
%s Especifica uma cadeia de caracteres
Na <lista de endereços das variáveis> é necessário passar o endereço de cada variável, isto é feito
escrevendo o operador & antes do nome de cada variável.
Exemplos:
float salario;
char sexo;
int idade;
printf (“Digite o salário: ”);
scanf (“%f”, &salário);
printf (“Digite a idade e o sexo: ”);
scanf (“%d %c”, &idade, &sexo);
Ao reconhecer que o usuário pressionou enter o computador armazena o valor digitado na variável e
volta à execução do programa.
Vale ressaltar que o especificador %c não pula os caracteres brancos (caractere espaço ‘ ‘, caractere de
tabulação ‘\t’ ou caractere de nova linha ‘\n’). Assim, se o usuário teclar um caractere branco antes de
teclar o caractere a ser lido, o código do branco será capturado, e o caractere que realmente interessava
somente será capturado em uma nova chamada da função scanf. Para resolver este problema, ou seja,
se desejarmos ignorar todas as ocorrências de caracteres brancos que, porventura, antecedam o
caractere que desejamos capturar, basta incluir um espaço em branco no formato, antes do
especificador.
Exemplo:
char sexo;
printf (“Digite o sexo: ”);
scanf (“ %c”, &sexo);
Outra forma de resolver o problema é usar a função fflush com o argumento stdin antes da execução
de um scanf com o especificador %c. A função fflush (stdin) limpará o buffer associado ao teclado (stdin
– standard input).
Exemplo:
char sexo;
printf (“Digite o sexo: ”);
fflush (stdin);
scanf (“ %c”, &sexo);
10 - Comandos de Decisão
São comandos que causam desvio no processamento, permitindo que um determinado bloco de
comandos possa ser escolhido ou não para a execução.
10.1 - Comando if
Sintaxe:
if ( <condição> )
{
<bloco de comandos>
}
A <condição> deve ser uma expressão que retorne um valor falso (0) ou verdadeiro (diferente de 0).
Quando a <condição> retorna o valor lógico verdadeiro o <bloco de comandos> é executado. Caso
contrário, o comando seguinte ao comando if é executado.
As chaves { } são opcionais quando o <bloco de comandos> for composto por apenas um comando.
Sintaxe:
if ( <condição> )
{
< bloco de comandos 1 >
}
else
{
< bloco de comandos 2 >
}
Quando a <condição> retorna o valor lógico verdadeiro o <bloco de comandos1> é executado. Caso
contrário, o < bloco de comandos2> é executado.
As chaves { } são opcionais quando o <bloco de comandos> for composto por apenas um comando.
Sintaxe:
switch ( <seletor> )
{
case <valor1> :
< bloco de comandos executado se seletor = = valor1 >;
break;
case <valor2> :
< bloco de comandos executado se seletor = = valor2 >;
break;
...
default :
< bloco de comandos executado se seletor diferente de todos os valores >;
break;
}
Permite que um ou mais < blocos de comandos> sejam executados, dependendo do valor do <seletor>.
O valor do <seletor> é comparado com cada um dos <valores>. Se existir um <valor> igual ao do
<seletor> o < bloco de comandos> relacionado é executado até encontrar um break. Se o comando
break for omitido a execução continua com os comandos dos case seguintes.
Se o valor do <seletor> for diferente de todos os valores dos case o < bloco de comandos> relacionado
a clausula default é executado.
A clausula default é opcional e pode aparecer em qualquer posição, mas normalmente é colocada no
final.
Quando um mesmo < bloco de comandos> deve ser executado para diferentes valores, devemos
encadear uma seqüência de case sem break, e o < bloco de comandos> é colocado no último dos case,
que conterá um break.
Exemplo:
#include <stdio.h>
#include <stdlib.h>
main()
{
int n;
printf("Digite um numero inteiro no intervalo [2, 6]: ");
scanf ("%d", &n);
switch (n)
{
case 2 : case 4 : case 6 :
printf("numero par\n");
break;
case 3 : case 5 :
printf("numero impar\n");
break;
default :
printf("valor fora do intervalo\n");
break;
}
system("PAUSE");
}
11 - Comandos de Repetição
Sintaxe:
while ( <condição> )
{
< bloco de comandos>
}
Antes de executar o < bloco de comandos> a <condição> é avaliada. Caso seja verdadeira o <bloco de
comandos> é executado. Caso contrário, o comando seguinte ao comando while é executado.
Supondo que o < bloco de comandos> seja executado, após a execução o processamento é desviado
para o início do comando while, e a <condição> é novamente avaliada.
Observe que a <condição> deve ser tornar falsa em algum momento. Caso contrário, teremos,
teoricamente, infinitas repetições (loop).
Observe ainda que se a <condição> for falsa na primeira avaliação (quando o while é iniciado) o < bloco
de comandos> não é executado vez alguma.
As chaves { } são opcionais quando o <bloco de comandos> for composto por apenas um comando.
Sintaxe:
do
{
< bloco de comandos>
}
while ( <condição> );
Observe que como a <condição> é testada no final de cada iteração, o <bloco de comandos> é
executado pelo menos uma vez.
Observe que a <condição> deve ser tornar falsa em algum momento. Caso contrário, teremos,
teoricamente, infinitas repetições (loop).
As chaves { } são opcionais quando o <bloco de comandos> for composto por apenas um comando.
Sintaxe:
for ( <expr de inicialização> ; <condição> ; <expr de incremento ou decremento> )
{
<bloco de comandos>
}
Em sua forma mais simples, a <expr de incialização> é um comando de atribuição que o compilador usa
para estabelecer a variável de controle do for. A <condição> é uma expressão de relação que testa a
variável de controle do for contra algum valor para determinar quando o loop terminará. O <expr. de
incremento ou decremento> define a maneira como a variável de controle do loop será alterada cada vez
que o <bloco de comandos> for repetido.
As chaves { } são opcionais quando o <bloco de comandos> for composto por apenas um comando.
Passo 3:
3 Executa o <bloco de comandos>
Passo 4: Retorna ao início do comando FOR e executa a <expr de incremento ou decremento>
Passo 5: Vai para o Passo 2.
O comando for
for ( <expr de inicialização> ; <condição> ; <expr de incremento ou decremento> )
{ < bloco de comandos> }
é equivalente a:
<expr de inicialização>
while ( <condição> )
{
< bloco de comandos>
<expr de incremento>
}
Declaração:
<tipo do dado> <nome do vetor> [<tamanho>];
Exemplo:
float notas [5]; //notas é uma variável do tipo vetor composto por 5 componentes do tipo float.
Componente
Supondo que o vetor notas armazene os valores 7, 10, 9.5, 8 e 6.5 teremos;
0 1 2 3 4
notas = 7 10 9.5 8 6.5
Observe que o acesso a cada componente do vetor é feito através de um índice. A indexação começa de
zero e vai até <dimensão> -1.
A referência é feita pelo nome do vetor seguido, entre colchetes, pelo índice do componente que se
deseja referenciar. No exemplo, o terceiro componente é referenciado por notas[2].
Exemplo:
main ()
{
int n;
do {
printf (“informe o número de elementos do vetor: “);
13 - Pesquisa em Vetores
Exemplo: uso do Método de Pesquisa Seqüencial para localizar proc = 7 no vetor v abaixo.
0 1 2 3 4 VERIFICA:
v= 13 21 7 9 14 v[0] = proc? não
v[1] = proc? não
v[2] = proc? sim, a busca é encerrada, retorna 2
Utilizado exclusivamente em vetores ordenados, é mais eficiente que o Método de Pesquisa Seqüencial.
Trabalha com três índices:
limInf: indicando o início lógico do vetor
limSup: indicando o fim lógico do vetor
meio: indicando a posição pesquisada no vetor
A cada iteração o método compara o valor procurado com o elemento do vetor apontado por meio. Caso
sejam iguais, o processo de pesquisa é encerrado. Caso contrário reposiciona os três índices e, em
seguida, realiza uma nova comparação descartando alguns componentes do vetor. Chamaremos este
novo vetor após o descarte de vetor lógico.
Para reposicionar os três índices devemos saber a forma de ordenação do vetor. A forma de
reposicionamento descrita a seguir supõe o vetor em ordem crescente. Caso este esteja em ordem
decrescente basta trocar menor por maior e maior por menor nas descrições abaixo.
• Se o valor procurado é menor que o valor no índice meio do vetor continue a pesquisa na metade inferior do
vetor lógico. Ou seja, faça limSup = meio – 1 e não altere limInf. Observe que a mudança em limSup causa
uma alteração em meio.
• Se o valor procurado é maior que o valor no índice meio do vetor continue a pesquisa na metade superior do
vetor lógico. Ou seja, faça limInf = meio + 1 e não altere limSup. Observe que a mudança em limInf causa
uma alteração em meio.
A busca termina quando o valor procurado é encontrado ou quando limInf ultrapassa limSup. O último
critério de parada indica que o valor procurado não existe no vetor. A posição do valor procurado,
quando encontrado, retorna como resultado da pesquisa.
Exemplo: Método de Pesquisa Binária para localizar proc = 10 no vetor v ordenado de forma crescente.
No início do processo os três índices são inicializados e posicionados como descrito anteriormente. As comparações se iniciam e
os devidos reposicionamentos dos ponteiros são realizados.
Primeira Comparação:
0 1 2 3 4 5 6 7 8 9
v= 2 3 5 6 7 10 11 15 20 32
Segunda Comparação:
0 1 2 3 4 5 6 7 8 9
v= 2 3 5 6 7 10 11 15 20 32
Terceira Comparação:
0 1 2 3 4 5 6 7 8 9
v= 2 3 5 6 7 10 11 15 20 32
limInf = 5 limSup = 6
Verifica: meio = 5
proc = v[meio] ? SIM - o processo de pesquisa é encerrado
14 - Ordenação de Vetores
Ordenar um vetor significa classificar seus elementos em ordem crescente ou decrescente. Na literatura
existem diversos algoritmos para este fim, cada um apresentando maior ou menor eficiência de acordo
com os dados de entrada. Vamos estudar um destes métodos em particular: o Método da Bolha ou
Bubble Sort.
Uma iteração do Método da Bolha consiste em “varrer” o vetor comparando dois a dois os elementos
adjacentes. Caso estes estejam em posições invertidas o método efetua a troca de posições.
Durante todo o processo de ordenação o método trabalha com o índice limSup, que inicialmente aponta
para o último elemento do vetor e a cada iteração é decrementado de uma unidade, passando a apontar
para o elemento limSup -1 do vetor. As iterações se repetem até que o método perceba que o vetor está
completamente ordenado.
Exemplo: uso do Método da Bolha para classificar, em ordem crescente, o vetor v abaixo.
0 1 2 3 4 Início do Processo
v= 5 1 9 3 4
limSup = 4
0 1 2 3 4 Primeira Iteração
v= 1 5 9 3 4 Compara v[0] com v[1] e os troca de posição
limSup = 4
0 1 2 3 4 Primeira Iteração
v= 1 5 9 3 4 Compara v[1] com v[2] e não os troca de posição
limSup = 4
0 1 2 3 4 Primeira Iteração
v= 1 5 3 9 4 Compara V[2] com V[3] e os troca de posição
limSup = 4
0 1 2 3 4 Primeira Iteração
v= 1 5 3 4 9 Compara V[3] com V[4] e os troca de posição
limSup = 4
Observe que, após comparar os elementos adjacentes dois a dois, do índice 0 até o índice limSup, o
maior elemento está na última posição. Contudo o vetor continua desordenado.
Uma nova iteração se faz então necessária. No entanto, observe que o valor no último índice do vetor já
está em sua posição definitiva. Assim, o último elemento do vetor não precisa mais participar do
processo de comparação. Faz-se então limSup = limSup – 1.
0 1 2 3 4 Segunda Iteração
v= 1 5 3 4 9 Compara V[0] com V[1] e não os troca de posição
limSup = 3
0 1 2 3 4 Segunda Iteração
v= 1 3 5 4 9 Compara V[1] com V[2] e os troca de posição
limSup = 3
0 1 2 3 4 Segunda Iteração
v= 1 3 4 5 9 Compara V[2] com V[3] e os troca de posição
LimSup = 3
Novamente observe que, após comparar os elementos adjacentes dois a dois, do índice 0 até o índice
limSup, os dois maiores valores estão nas duas últimas posições. Como o segundo maior já se encontra
em sua posição definitiva faz-se limSup = limSup – 1.
Observe ainda que o vetor já está ordenado. Contudo, como o método ainda não percebeu este fato uma
nova iteração se faz necessária.
0 1 2 3 4 Terceira Iteração
v= 1 3 4 5 9 Compara V[0] com V[1] e não os troca de posição
limSup = 2
0 1 2 3 4 Terceira Iteração
v= 1 3 4 5 9 Compara V[1] com V[2] e não os troca de posição
limSup = 2
O método, após comparar os elementos adjacentes dois a dois, do índice 0 até o índice limSup, e não
conseguir realizar uma única troca percebe a ordenação do vetor e encerra o método.