Buscar

CONTEUDO PROVA - LINGUAGEM E TECNICAS DE PROGRAMACAO

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

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

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

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

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

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

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

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

INTRODUÇÃO A PROGRAMAÇÃO
· Dado: são as informações a serem processadas
· Instruções: são comandos que orientam o processamento feito por um computador
TIPOS DE DADOS
Em princípio, os computadores trabalham com quatro tipos de dados. Partindo destes, as linguagens de programação derivam outros mais específicos, ou com uma precisão maior. O tratamento lógico entre esses tipos derivados é o mesmo.
· Números inteiros: (negativo, nulo ou positivo): 1; 2; 44; 100; 0; -15; -99.
· Números reais: (negativo, nulo ou positivo): 0,12; 3,14159; 0,0000; -1,23. Uso mais comuns em valores em dinheiro, salário, preço total ou unitário, peso, média.
· Caracteres (chars) e cadeias (string): toda e qualquer informação composta por um conjunto de caracteres alfanuméricos. São identificados por estarem entre apóstrofos. Uma string é um conjunto de caracteres, assim ‘a’ é um caractere, e ‘avião’ é uma string. Uso mais comuns: nome, endereço, descrição.
· Numéricos: (‘0’....’9’)
· Alfabéticos (‘A’...’Z’...’a’...’z’)
· Especiais (‘#’,’?’,’!’,’@’)
· Lógicos: valores booleanos T (true) ou F (false). Uso comum em controle de fluxo de programa, flags.
CONSTANTES
Dados que não sofrem nenhuma variação durante a execução do programa. Seu valor deverá ser o mesmo do início ao fim da execução do programa.
As constantes podem ser de qualquer tipo de dado e, normalmente, são definidas em partes específicas de um programa.
Exemplo:
#definido PI = 13,141617 (NUNCA MUDA).
VARIÁVEIS
São espaços reservados na memória principal do computador em que os dados são armazenados para reutilização posterior
VARIÁVEIS – NOMENCLATURA
É recomendado dar um nome que lembre a informação armazenada seguindo as seguintes regras:
· O primeiro caractere deve ser uma letra;
· Os nomes podem ser formados por letras, dígitos e underline;
· Podem ter qualquer comprimento.
O computador, para poder trabalhar com as informações, precisa saber a localização do dado na memória. Portanto, cada variável criada possui um endereço em uma posição de memória, ou seja, um número representado por meio da notação hexadecimal que indica o endereço de memória em que está armazenada a informação.
Ao definirmos uma variável como caractere ou string alocaremos até 225 bytes, um byte para cada caractere da string. Com relação a strings, podemos utilizar o valor entre aspas ou entre apóstrofos.
VARIÁVEIS – DECLARAÇÃO
Criar uma variável significa reservar um espaço na memória do computador dando-lhe um nome e determinar qual o tipo de dado que essa memória armazenará.
Exemplo:
Em pseudocódigo:
var
 <nome da variável1>, ...<nome da variável>: <tipo>
var
 nome, código: Cadeia
 contador, idade: Inteiro
Em C:
int (variável de números inteiros) idade (nome da variável);
int idade;
OPERADORES
São elementos que atuam sobre operando para produzirem um resultado. Ao tomarmos a expressão aritmética 2 + 3, temos dois operandos, os números 2 e 3, que são relacionados pelo operador de soma (+), fazendo a operação de adição. Os operadores podem ser binários, quando atuam sobre dois operadores (soma, subtração, etc.), ou unário, quando atuam somente sobre um operador (como o sinal negativo em um número).
OPERAÇÃO DE ATRIBUIÇÃO (← ou <-)
As variáveis armazenam os valores para uso posterior no transcorrer do programa. Para armazenar um valor em uma variável utilizamos o operador de atribuição, que é representado por uma seta apontando para a esquerda (← ou <-).
Exemplo:
Em pseudocódigo:
<variável> ← valor
var
 nome: cadeia
 idade: inteiro
inicio
 nome ← “Tainara Motizuki”
 idade ← 28
fim
OPERADORES ARITMÉTICOS
A divisão DIV e MOD dão resultados diferentes, o exemplo será a divisão de 9 por 2.
Para entender o MOD e o DIV, é importante ter em mente que as operações envolvem apenas números inteiros:
Resumindo:
9 / 2 = 4,5
9 / 2 em DIV = 4
9 / 2 em MOD = 1
OPERADORES RELACIONAIS
OPERADORES LÓGICOS
· Operador AND (E): o resultado somente será verdade quando ambos os operadores forem verdadeiros.
· Operador OR (OU): o resultado somente será verdadeiro quando pelo menos um dos operadores for verdadeiro.
· Operador NOT (NÃO): é um operador unário, tem apenas um operador e inverte o valor do resultado desse operando.
· Operador XOR (OU EXCLUSIVO): é o menos utilizado; seu resultado somente será verdade quando os dois operandos forem diferentes.
PRIORIDADE NA AVALIAÇÃO DE EXPRESSÕES
Existe uma sequência para realizar as operações. Portanto deve-se obedecer à seguinte ordem:
· Parênteses e funções (resolvidos da esquerda para a direita);
· Multiplicação (*), divisão (/ e DIV) e resto (MOD) (resolvidos da esquerda para a direita);
· Soma e subtração;
· Operadores relacionais: >,<,>=,<=,=,<>;
· Operador lógico NOT;
· Operador lógico AND;
· Operador lógico OR;
Exemplo: resolver a seguinte expressão:
X= ((1+ 2 * 3) <= (4 + 6 / 2)) e (not ((6+1) <> (10-3)))
X= ((1+ 6) <= (4 + 3)) e (not (7 <> 7))
X= (7 <= 7) e (not (Falso)
 X= (true) e (true)
X= true
LINEARIZAÇÃO
O computador não reconhece as fórmulas matemáticas armadas, por exemplo, para calcular a área de um triângulo, aprendemos que:
Para que o computador entenda a fórmula, precisamos, manualmente, fazer o processo de linearização, que consistem em remontar a fórmula utilizando parênteses e escrevendo-a em apenas uma linha. Assim, a fórmula da área do triângulo fica:
Área <- (base * altura) /2
ESTRUTURA SEQUENCIAL
É um conjunto de comandos que serão executados numa sequência linear de cima para baixo, linha a linha. Pode aparecer em qualquer estrutura de controle, agrupada ou não por blocos.
 
Quando é feito o uso de fluxograma, a estrutura sequencial é caracterizada por um único fluxo de execução no diagrama. Em pseudocódigos, a estrutura sequencial caracteriza-se por um conjunto de comandos dispostos ordenadamente.
ESTRUTURA DE UM PSEUDOCÓDIGO
Não existe uma estrutura rígida de escrita de um pseudocódigo. Conforme a leitura, tal estrutura pode mudar, mas o importante é que transmita a ideia. Exigir regras fixas e pouco flexíveis torna o pseudocódigo em uma linguagem de programação. Porém o mínimo de formalidade é necessário para um bom entendimento.
Com base nas formas mais comuns encontradas na literatura, um pseudocódigo tem três partes:
· Cabeçalho com o nome do programa;
· Uma seção para a declaração de constantes e das variáveis;
· O corpo do programa, em que é feita a programação sequencial.
Segue um algoritmo completo: em azul-claro, temos o cabeçalho; em bege, a declaração das variáveis; e, em verde, o corpo do programa.
Temos também algumas regras de etiqueta, ou boa educação. Essas regras não estão diretamente ligadas ao processamento em si, mas facilitam a compreensão do programa, tanto pelo autor quanto pelas pessoas que, posteriormente, tentarão entender o programa. Usando o mesmo código, veremos dois conceitos importantíssimos: o comentário e a identação (são válidos tanto o termo indentação, um anglicismo vindo de to indent, quanto o oficialmente adotado endentação).
· Comentários: servem para lembrar ou explicar o que está acontecendo em determinado local do código. Usa-se // para comentar uma linha e /* */ para um comentário maior com mais linhas.
· Identação: é útil para separar blocos de programação, afastando e realinhando as linhas da margem esquerda. A identação na confecção do pseudocódigo é fundamental, e muitas vezes, os códigos são considerados inválidos caso esta não seja feita. No código a seguir, as linhas verticais são os blocos, e as setas horizontais são as identações.
ENTRADA E SAÍDA DE INFORMAÇÕES
Instrução primitiva de dados
Para podermos ver no monitor, ou em uma impressora, precisamos ter uma instrução específica, esta é chamada de instrução primitiva. Primitiva, pois, é uma instrução nativa, que não requer programação e já vem pronta para ser utilizada. Essa instrução é a maneira que temos para mostrar as informações contidas na memória dos computadores, para que o usuário possa visualizá-la. A sintaxe é:
Uma <lista_de_variáveis> é um conjunto de nomes de variáveis separadospor vírgulas:
Exemplo:
Escreva (i, j, total)
Escreva (“entre com a taxa de juro % mensal”)
Escreva (“prestação “, i, “valor”, parcelamensal))
Exemplo 2: o algoritmo a seguir mostra o uso da instrução de saída. O programa faz o calculo do preço total de cinco produtos que custam cinco reais cada, apresentando na tela o resultado.
 
Instrução primitiva de entrada de dados
No algoritmo do exemplo anterior, a interação com o computador ainda não está completa. O programa faz o cálculo e mostra o resultado na tela. Os valores do preço unitário (5.0) e da quantidade (10) são fixos. O ideal seria poder alterar esses valores a cada execução do programa. Para isso, teríamos de fazer a interação de introduzir um valor no programa, durante a sua execução, por meio do teclado.
A instrução primitiva, no caso, é o leia. Essa instrução interrompe a execução e espera a interação do usuário para introduzir uma informação, que será armazenada na variável indicada pelo comando e que será utilizada no transcorrer do programa.
Leia (<variável>)
Leia (<lista de variáveis>)
Exemplo: voltando para o programa do exemplo anterior, agora será alterado para entrar com os valores da quantidade e do preço do produto.
 
TESTE DE MESA
Um algoritmo precisa ser validado pela utilização do teste de mesa. Nesse teste, você assume o papel do processador e fica responsável por executar cada linha do código. O teste permite verificar se o código está realmente executando a função para a qual foi criado e se existe algum erro de lógica nos passos apresentados.
Para fazer um teste de mesa, inicialmente, vamos estudar um código.
O programa foi escrito para calcular o valor de um termo de uma progressão aritmética (PA) que fica determinada pela sua razão (r) e pelo primeiro termo (a1). Esta é dada pela fórmula:
Vamos fazer o teste de mesa verificando o resultado para r = 5, a1 = 12 e n =4.
Inicialmente, vamos verificar qual o valor esperado efetuando a matemática a fórmula:
Portanto, o valor esperado é 27.
Como estamos assumindo o papel de um computador, executaremos sequencialmente cada linha do programa.
· Iniciando a execução, o computador está com a memória totalmente vazia
· Na primeira linha, encontramos a identificação do programa e assim reservamos a memória para o programa PA:
 
· Na linha seguinte, encontramos um comentário (//), portanto este será ignorado e a memória continuará sem alteração.
· A seguir encontramos a seção de declaração das variáveis. Nesse ponto, o computador criará os espaços na memória para as variáveis. Em nossa memória simulado, cada variável será representada em uma coluna:
 
· Montadas as variáveis, é iniciado o processamento do programa, que encontra mais um comentário e encontrará um comando de saída (escreva). Para simular a saída, criaremos uma nova coluna, chamada tela, em que serão simuladas as informações de entrada e saída:
· No passo seguinte, o programa esperará que o usuário digite um valor, que será atribuído à variável razão. Entramos com o valor 5, pois este foi definido como precondição para a simulação. Assim a informação será armazenada na variável razão:
· O computador encontra, no passo seguinte, mais uma instrução de saída. O texto será mostrado na tela.
· A seguir, é feita a leitura, para atribuir valor à variável a1. A variável a1 receberá 12.
· Novamente, é executada a saída de um texto. O texto será exibido na tela:
· Finalmente, será feita a leitura do valor do termo que queremos saber na PA. Nesse momento, a variável razão contém o valor 5, a variável n contém 4, a variável contém 12 e a variável na continua vazia:
· É efetuado o cálculo substituindo-se os nomes das variáveis pelo seu conteúdo e atribuindo o resultado à variável an. O resultado 27 será armazenado na variável an:
· O passo seguinte é mostrar o resultado. Como n vale 4, an vale 27, e a saída será “O elemento 4 é 27”
· A última linha é apenas uma indicação de encerramento do programa.
Ao final da simulação, o valor foi 27; correspondendo ao calculado matematicamente, podemos considerar o programa correto.
INTRODUÇÃO À LINGUAGEM C
A linguagem C pertence a uma família de linguagens cujas características são: portabilidade, modularidade, compilação separada, recursos de baixo nível, geração de código eficiente, confiabilidade, regularidade, simplicidade e facilidade de uso.
Essa linguagem é adequada para programação estruturada, tendo aplicação, principalmente, no desenvolvimento de sistemas operacionais, planilhas eletrônicas e gerenciadores de bancos de dados.
A linguagem C é considerada de médio nível. Não é uma linguagem de máquina, chamadas de baixo nível, como o Assembly, nem de alto nível, em que a própria linguagem fornece todos os recursos para desenvolvimento do programa, como o Visual Basic.
REGRAS DA LINGUAGEM
Como toda linguagem de programação, a linguagem C é muito rígida na sua sintaxe. Sintaxe são regras detalhadas para que um programa possa ser executado.
As regras estão relacionadas com os tópicos a seguir:
· Tipos: definem as propriedades dos dados manipulados em um programa;
· Declarações: definem o identificador, para alocar memória, definir conteúdo inicial e determinar funções;
· Expressões: fórmulas que atribuem e alteram valores, bem como fazem chamada de funções de estrada e saída;
· Funções: são os subprogramas em C, que por sua vez, são chamados por outras funções executando tarefas específicas. Há funções básicas que estão definidas nas bibliotecas-padrão da linguagem, e outras que são desenvolvidas por terceiros, com rotinas mais específicas. As funções printf() e scanf(), por exemplo, que permitem, respectivamente, escrever na tela e ler os dados a partir do teclado, fazem parte da biblioteca básica. O programador também pode escrever as suas próprias funções.
A primeira função que o programa executa é o main (), portanto é obrigatória a sua declaração no programa principal.
Outras regras importantíssimas:
· A linguagem é case sensitive; isso quer dizer que as letras maiúsculas são diferentes das letras minúsculas, na identificação de comandos, variáveis e funções.
· Os comando são separados por ponto e vírgula ( ; ), que deve ser usado com muito cuidado, principalmente, antes de blocos de comandos.
· A linguagem permite o uso de comentários, que são colocados no texto entre “/*” e “*/”, quando se quer escrever mais de uma linha. O uso do “//” também serve como comentário, e, neste caso, o compilador ignorará tudo o que estiver escrito a partir dele até o fim da linha.
· Pela definição padronizada pela ANSI, existem 32 palavras reservadas que formam a linguagem de programação C. Conforme o compilador, poderão existir mais palavras reservadas, todas escritas em minúsculo. Nenhuma palavra reservada poderá ser utilizada para dar nome a variáveis e funções, pois isso gerará erro ao compilar.
· Os identificadores são nomes usados para se fazer referência a variáveis, funções, rótulos e vários outros objetos definidos pelo programador. Como norma, conforme vimos no pseudocódigo, o primeiro caractere deve ser uma letra ou um sublinhado, e o restante podem ser números, letras ou sublinhado; apenas os 32 primeiros caracteres de um identificador são significativos. Como já foi dito, a linguagem C é case sensitive, ou seja, diferencia letras maiúsculas e minúsculas.
ESTRUTURA DE UM PROGRAMA EM C
Para programar em C partindo do zero é necessário apenas o bloco da função main(). Como há a necessidade de interações, é preciso colocar as bibliotecas no programa, e isso é feito em primeiro lugar.
Para termos uma ideia mais clara da estrutura, vamos elaborar o primeiro programa e compreender cada uma das linhas.
Ao executar o programa, teremos uma mensagem no console do DOS dizendo “meu primeiro programa em C”. Apesar de ser um programa muito simples, temos a estrutura mínima de um programa nessa linguagem. Vamos analisar cada parte dessa estrutura a seguir:
O comando include informa ao compilador que ele deve incluir a biblioteca stdio.h. Nessabiblioteca há uma série de funções de entrada e saída úteis. Sempre que quiser usar funções relativas à entrada e saída, verifique se o arquivo stdio.h as contém. A linguagem C fornece dezenas de bibliotecas com milhares de funções úteis. 
Como vimos anteriormente, o compilador ignora os comentários.
Define o nome da função main. Todo programa em C precisa ter essa função, pois esta é a premissa de funcionamento e é a função que o programa executa ao ser inicializado. A palavra void indica que a função não retorna valor, conforme veremos mais adiante.
Indica o início do bloco do programa principal, o ponto em que o processamento começará.
Função que mostra na tela uma informação desejada. Está contida na biblioteca stdio.h, e é por isso que este foi incluso no programa. Corresponde ao escreva do pseudocódigo.
Fecha o bloco da função main(), encerrando o programa.
O programa corresponde ao pseudocódigo:
TIPOS DE INFORMAÇÕES, VARIÁVEIS E CONSTANTES
Na linguagem C, os tipos primitivos sofreram modificações, visando aumentar a precisão ou adaptar a compatibilidade.
A sintaxe de declaração de uma variável será:
Para declarar uma constante, acrescenta-se a palavra-chave const no início e atribui-se um valor a ela.
Sintaxe:
A tradução do pseudocódigo ficará assim:
A linguagem permite também atribuir valor no momento da declaração da variável, assim como declarar muitas variáveis do mesmo tipo na mesma linha, ou realizar ambas as ações.
Exemplo:
Para tipos lógicos e as cadeias de caracteres, a linguagem C tem um tratamento específico:
· Tipo lógico: a linguagem C trata como true o valor inteiro 1 e como false o valor inteiro 0; assim, a ausência de tipo lógico é compensada pelo correspondente numérico. Na versão C++, a linguagem passa a incorporar o tipo bool.
Para contornar a ausência do tipo lógico na linguagem C, são utilizados artifícios como o do código a seguir:
· Tipo caractere e string: a linguagem C não trata os caracteres como tipos literais, mas como números. Assim, o tipo char usa 8 bits ou um byte, armazenando, portanto, um número cujo valor máximo é 255. Cada caractere tem um correspondente numérico, obedecendo a uma tabela. Normalmente, obedece à tabela chamada ASCII.
Conforme essa tabela, ao armazenarmos a letra “A” em uma variável do tipo char, o conteúdo será o número 65.
Exemplo de aplicação:
Para armazenarmos quatro caracteres, devemos alocar cinco espaços:
Quando o tamanho for indefinido, será necessário colocar a identificação de fim de caractere.
· Constantes de barra invertida: o C possui algumas constantes para facilitar a exibição de resultados na tela, a manipulação de string ou a impressão. São caracteres que podem ser usados como quaisquer outros.
OPERADORES
A correspondência entre o pseudocódigo e a linguagem C, dos operadores matemáticos, é mostrada na tabela abaixo:
A linguagem C tem, ainda, algumas sintaxes específicas não presentes nos pseudocódigos.
· Atribuição múltipla: nesse caso, o número cinco é atribuído, inicialmente, à variável x, e, em seguida, o conteúdo da variável x (número cinco) é atribuído à variável y.
y = x = 5;
· Operadores de incremento e decremento: são operadores não convencionais que atuam sobre a própria variável, aumentando ou diminuindo uma unidade. A sintaxe é:
<variável>++
ou
++<variável>
Exemplo de aplicação: 
A variável a, ao executar a operação a++, incrementa em uma unidade o valor guardado. As operações a++ ou ++as têm o mesmo resultado, porém o mecanismo do processamento trabalha de forma diferente.
Vamos supor que a variável a armazene o valor 5.
x = a++;
Esse código atribui 5 a x, trabalhando da seguinte forma: o conteúdo de a é atribuído a x e depois é feito o incremento. Contudo, veja outro caso:
x = ++a;
Nesse exemplo, atribuímos 6 a x, pois é feito o incremento na variável a, e depois o resultado é atribuído a x.
No final, ambos passam a valer 6, pois seu valor foi incrementado em uma unidade, mas o valor final de x é diferente em cada um dos casos.
Para entender melhor, veja a comparação a seguir:
Os operadores de incremento e decremento podem ser aplicados somente a variáveis; uma expressão do tipo x = (i +1)++ é ilegal.
· Operadores de atribuição: resultam na substituição do conteúdo do termo à esquerda da expressão. Com exceção da igualdade, todos os operadores resultam em formas similares de execução.
· Operador relacional: 
· Operador lógico: 
· Conversão do tipo (cast): o que acontece quando ocorre a divisão entre duas variáveis numéricas de tipos diferentes? Na linguagem C, ocorre uma avaliação automática da expressão, ajustando, antes, o resultado para o tipo de maior precisão. Assim, se dividirmos uma variável inteira com o número 5 por uma variável double com valor 2,5, o programa converterá a primeira variável para double e realizará o cálculo, devolvendo um valor double.
· Precedência na ordem de avaliação dos operadores: obedece a mesma sequência vista no pseudocódigo, exceto pelos operadores característicos da linguagem C:
! ++ -- - (cast)
ENTRADA E SAÍDA DE INFORMAÇÕES
A linguagem C não possui comando de entrada e saída. Esses comandos são feitos por meio de funções. Para utilizar tais funções, existe uma biblioteca, o stdio.h. A inclusão da biblioteca é feita no início do programa, por meio da instrução:
#include <stdio.h>
· Saída: a função que executa a visualização de informações pela tela é o printf, segundo um determinado formato. A sintaxe da função é:
printf(“formato”, lista de variáveis/expressões)
A função é formada por duas partes. A primeira determina o formato da saída. Para cada valor contido em uma variável deve existir um especificador do formato de saída. As variáveis ficam listadas na segunda parte dos parâmetros da função. Os especificadores de formato determinam o tipo e a precisão dos valores que queremos mostrar na tela. Esses especificadores são precedidos do caractere %.
Exemplo de aplicação:
Ao executar:
Resultará em: 
Os caracteres “|” mostram o limite dos campos.
Alterando o programa:
teremos a seguinte saída:
Notamos que o espaço ocupado pelo 34 ficou mais largo, e o ocupado pelo 5.6, além de estar mais largo, tem um zero a mais.
Exemplo de aplicação 2: 
Traduzir o seguinte pseudocódigo:
· Entrada: os valores digitados no teclado são capturados pela função scanf, que também pertence à biblioteca stdio.h. Assim como o printf tem duas partes, uma que determina o formato de leitura e a segunda variável, que irá receber o valor digitado. A sintaxe da função é:
scanf ( “ formato “, &variável)
Os especificadores de tipo do formato são similares aos utilizados na função printf. A função scanf utiliza especificadores diferentes para o tipo float e o tipo double.
A diferença é que o formato deve ser seguido por uma lista de endereços de variáveis (na função printf, passamos os valores de constantes, variáveis e expressões). No tópico sobre ponteiros, esse assunto será tratado em detalhes. De maneira mais ampla, para o scanf ler um valor e atribui-lo a uma variável, é necessário passar o endereço da variável que receberá o valor digitado. O operador & retorna o endereço de uma variável. Assim, para ler um inteiro, devemos ter:
O formato também pode obrigar a digitar entrada dentro de um dado padrão. Por exemplo, para obrigar a entrada de dois números inteiros separados por dois-pontos, a sintaxe é:
scanf (“%d:%d”, &hora, &min);
Um espaço em branco dentro do formato faz que sejam ignorados eventuais brancos da entrada.
Exemplo de aplicação:
Tradução:
Executando:
TOMADA DE DECISÕES
Até agora, os programas foram executados em sequência, de cima para baixo, mas podem acontecer situações em que alguns comandos não sejam adequados e, por isso, não necessitem ser executados. Em outros casos, pode ser necessário optar por executar diferentes blocos de comandos, conforme a situação. Essas estruturas são chamadas de condicionais.
CONDICIONAIS
São utilizadas quando há a necessidade de tomar decisões, ou quando é preciso efetuar comparações.Nesse tipo de estrutura, uma operação lógica (<condição>) é avaliada. Se o resultado dessa avaliação for true, então um determinado conjunto de instruções será executado. Se o resultado for false, um comando diferente será executado.
IF... THEN (SE ENTÃO)
A primeira situação é quando uma condição é testada, e caso seja verdadeira, um bloco de comando é executado. Essa estrutura se chama If... then (se então).
Sintaxe:
se (if) <condição> então (then)
 comando 1... (neste caso a <condição> é verdadeira)
fimse
Ao encontrar a condição if (se), o programa entende que virá uma expressão cujo resultado é lógico. Caso essa expressão resulte em true, é executado o bloco de comandos entre o then (então) e o fimse. Caso a condição resulte em false, o bloco todo é ignorado, prosseguindo após o fimse.
IF...THEN...ELSE (SE ENTÃO SENÃO)
A segunda situação é quando uma condição é testada e, caso seja verdadeira, um bloco de comando é executado; e, caso seja falsa, um outro bloco de comando é executado. Essa estrutura se chama if... then... else (se então senão).
Sintaxe:
se (if) <condição> então (then)
 comando 1... (neste caso a <condição> é verdadeira)
senão (else)
 comando 2... (neste caso a <condição> é falsa)
fimse
O programa, ao encontrar a condição if, entende que virá uma expressão cujo resultado é lógico. Caso essa expressão resulte em true, é executado o bloco de comandos entre o then e o else, passando a execução para o primeiro comando após o fimse. Caso a condição resulte em false, é executado o bloco entre o else e o fimse.
ESTRUTURA CONDICIONAL IF (SE) ANINHADA
Na programação, dentro de um bloco, os comandos (que, por enquanto, são executados entre o then e o else ou entre o else e o fimse) podem ser quaisquer dos aprendidos até agora, inclusive, o próprio if.
O aninhamento de condicionais é muito comum e exige um nível maior de raciocínio, portanto uma lógica mais apurada no momento da programação.
Sintaxe:
Um exemplo de if aninhado para uma consulta médica para facilitar o entendimento:
Assim, a identação passa a ser fundamental para o entendimento do programa. Para facilitar a visualização e o raciocínio fluir.
Exemplo de aplicação:
SWITCH CASE (ESCOLHA-CASO)
Por enquanto, foi visto apenas um teste em que a operação condicional apresenta apenas dois resultados possíveis. Se fosse necessário escolher um resultado dentre vários possíveis, teríamos de encadear várias condicionais.
Existe uma estrutura que evita o encadeamento de condicionais. Essa estrutura é chamada de switch case (escolha-caso). Essa estrutura é utilizada quando é necessário testar uma única expressão que produz um resultado dentre vários possíveis, ou, então, testar o valor de uma variável em que está armazenada uma determinada informação. Compara-se o resultado, obtido opção a opção, testando-se com os valores individuais fornecidos de cada cláusula.
Sintaxe:
switch (variável)
case (opção 1)
 bloco de instruções
case (opção 2)
 bloco de instruções
-
-
-
case (opção n)
 bloco de instruções
fimescolha
OU
Switch (variável)
Case (opção 1)
 Bloco de instruções
Case (opção 2)
 Bloco de instruções
.
.
Outrocaso:
 Bloco de instruções
Fimescolha
LABORATÓRIO
Na linguagem C, o comando correspondente ao se é o if.
Sintaxe:
if (expr) {
 Bloco de comandos 1
}
A sintaxe corresponde à estrutura:
Se <condição> então
 Bloco de comandos 1
Fimse
Deve ficar claro que, na linguagem C, se a condição for verdadeira, o programa irá executar o próximo comando ou bloco.
Assim:
If (true)
{
 Bloco de comandos 1
}
Exemplo de aplicação:
Converta o pseudocódigo:
Ao executarmos o programa com a entrada 5, temos a seguinte saída:
Executando com -5 na entrada, temos a seguinte saída:
OBS: um erro comum é colocar o símbolo de fim de comando ( ; ) após a condicional, anulando a estrutura do if.
Inclui-se a biblioteca stdio.h
Abre-se uma função void main() – função que não retorna valor.
Variável de número inteiro (int) nome da variável é “número”.
Imprime na tela “ente com um número: “.
Lê-se a informação digitada “%d” – sabemos que será digitado um número pois %d recebe um int.
&numero – vai retornar o valor digitado dento da variável numero criada acima.
SE o número for <0 imprime na tela “número negativo”.
SENÃO imprime na tela “número positivo”.
SWITCH CASE NA LINGUAGEM C
O comando switch para selecionar dentre um conjunto de possíveis casos corresponde ao escolha do pseudocódigo. Sua forma geral é:
switch (expr)
{
case 1:
 /* comandos executados se expr == opção 1 */
 break;
case 2:
 /* comandos executados se expr == opção 1 */
 break;
case 3:
 /* comandos executados se expr == opção 3 */
 break;
default:
 /* executando se expr for diferente de todos */
 break;
}
Exemplo de aplicação:
Fazer uma calculadora simples, que leia dois números e a operação:
Na linguagem C, temos mais dois casos de condicionais.
O primeiro caso é chamado de if-else-if, que é um complemento do if...else.
O funcionamento é idêntico ao do if... else, mas a estrutura é visivelmente próxima à do switch case.
O segundo caso é o operador ?. Trata-se de uma condicional que devolve um valor e envolve três expressões:
Condição?expressão 1:expressão 2;
O operador funciona da seguinte forma: se a condição resultar em verdadeiro, retornará o resultado da expressão 1; se a condição for falsa, retornará o resultado da expressão 2.
LAÇOS DE REPETIÇÃO
Uma das funções do computador, entre outras, é fazer operações repetitivas, que para o ser humano seriam muito enfadonhas. São muito comuns, durante o processamento de um programa, situações em que pode existir a necessidade de repetir um determinado conjunto de comandos por um certo número de vezes. Por exemplo: durante o processamento da folha de pagamento de uma empresa, o mesmo cálculo do salário conforme as horas trabalhadas é efetuado para cada um dos funcionários. Para evitar a repetição desse cálculo, utiliza-se a estrutura de repetição. As estruturas de repetição são também denominadas laços (loops).
Existem três comandos que executam a estrutura dos laços de repetição: o enquanto, o repita e o para. Apesar de todos terem a mesma funcionalidade, a de fazer repetições, o conforme o problema a ser resolvido, cada um deles apresenta uma característica mais adequada. Conforme o conhecimento prévio e a quantidade de laços executados, ou se o número de vezes em que o conjunto de instruções será executado (iteração) for indeterminado, as estruturas de repetição poderão ser classificadas em:
· Laços contados: quando se conhece previamente quantas vezes o comando composto no interior da construção será executado.
· Laços condicionais: quando não se conhece o número de vezes em que o conjunto de instruções no interior do laço será repetido, pois a condição testada é modificada pelas instruções do interior do laço.
É importante ter em mente que os laços de repetição têm um funcionamento automatizado, muito particular em cada uma das formas, e o entendimento desse mecanismo é fundamental para montar corretamente os programas.
A nomenclatura técnica para a execução de um laço completo é interação.
LAÇOS CONDICIONAIS
Quando existe blocos de programa que necessitam ser repetidos, porém não sabemos quantas vezes isso ocorrerá, utilizamos o laço condicional. No caso, são dois: o laço do repita até que e o do enquanto faça.
REPITA ATÉ QUE
No laço repita, o fluxo do programa encontra o comando propriamente dito e reconhece que é o início do bloco de repetição, seguindo o fluxo normal até encontrar o comando até que, no qual uma condição é testada. Se o resultado for falso, o fluxo será devolvido ao início do bloco. Se o resultado do teste for verdadeiro, o programa seguirá o fluxo, abandonando a repetição do bloco. O importante é saber que, nessa estrutura, o processo será repetido enquanto a condição testada for falsa.
Exemplo de aplicação em pseudocódigo:
Faça um algoritmo que processe a seguinte enquete: “você tem computador em casa?”, mostrando o número de pessoas que não possuem eo das pessoas que possuem computador. Para sair, dê a opção de escolha.
ENQUANTO FAÇA
O laço enquanto funciona da seguinte maneira: ao início do bloco de repetição, uma condição é testada. Se o resultado do teste for falso, então o bloco será ignorado, prosseguindo normalmente após o fimequanto. Caso o resultado do teste seja verdadeiro, o bloco será executado, e ao encontrar a instrução fimenquanto, o fluxo será devolvido à instrução enquanto, e a condição, testada novamente, até que se torne falsa. Resumindo, o processo será repetido enquanto a condição testada for verdadeira.
Exemplo de aplicação em pseudocódigo:
LAÇOS CONTADOS
São utilizados quando existir o conhecimento prévio do número de interações a ser executado. Essa estrutura é conhecida como o laço do para-até. O laço para utiliza uma variável que é contador, e a cada interação se atualiza esse valor, verificando se chegou ao seu limite.
Forma:
para <varcontrole> de <vl inicial> até <vl final> passo <passo> faça
fimpara
Exemplo de aplicação em pseudocódigo:
LABORATÓRIO
Na linguagem C, temos os três tipos de estruturas de blocos, porém com algumas diferenças.
DO... WHILE (REPITA ATÉ QUE)
Como visto no pseudocódigo no laço repita, o fluxo do programa encontra o comando propriamente dito, reconhece que é o início do bloco de repetição e segue o fluxo normal até encontrar o comando em que uma condição é testada. Na linguagem C, o comando que inicia o repita é o do segundo bloco demarcado pelas chaves.
A diferença entre o pseudocódigo e a linguagem C é que nesta, ao final, o teste é feito com o comando while (condição), executando novamente o laço se o resultado for verdadeiro. É o contrário do pseudocódigo, em que, caso o resultado do teste seja falso, o fluxo é devolvido ao início do bloco.
Assim, a tradução do programa da enquete usando do... while será:
OBS: o comando fflush serve apenas para limpar a área de leitura, pois, em alguns casos, quando ocorre a leitura de um caractere, podem acontecer erros.
Ao executarmos, obtemos a seguinte tela:
WHILE (ENQUANTO FAÇA)
Estruturalmente, o laço while não difere do pseudocódigo. O laço realizará as iterações do bloco de comandos enquanto o resultado da variável for verdadeiro. Quando a variável se tornar falsa, o bloco de comando parará de ser executado, e o programa prosseguirá no comando seguinte ao bloco.
A tradução do programa “enquete” usando o laço while será:
FOR (PARA ATÉ QUE)
Na linguagem C, a estrutura do funcionamento é semelhante ao do para do pseudocódigo, mas indicada de forma explícita.
Para exemplificar e deixar claro o seu funcionamento, serão apresentados alguns casos de tradução.
· CASO 1:
Pseudocódigo:
para i de 1 até 15 passos 2 faça
Linguagem C:
for ( i = 1; i<=15; i+=2)
· CASO 2:
Pseudocódigo:
para i de 3 até 15 faça
Linguagem C:
for ( i =3; i<=15, i++)
ou
for ( i = 3; i<=15; i=i+1)
· CASO 3:
Pseudocódigo:
para j de 30 até 10 passos -1 faça
Linguagem C:
for ( j = 20; j>=10; i--)
ou
for (j = 20; j>=10, i=i-1)
A tradução do programa utilizado na explicação fica:
A saída do programa fica:
ESTRUTRA DE DADOS
Como as informações estão organizadas dentro do computador, dentro das pastas, dentro dos arquivos? Os dados, de alguma forma, deverão estar dispostos para que seja possível realizar a escrita e a sua posterior recuperação de forma íntegra. Assim, as estruturas de dados são formas otimizadas de armazenamento e tratamento das informações eletronicamente.
DADOS HOMOGÊNEOS
Uma estrutura de dados que utiliza somente um tipo de dado é conhecida como de dados homogêneos. Variáveis compostas homogêneas são aquelas em que as posições de memória são identificadas por um mesmo nome e individualizadas por índices, e todos os conteúdos são compostos pelo mesmo tipo. Assim como vimos anteriormente os vetores (também conhecidos como estruturas de dados unidimensionais) e as matrizes (estruturas de dados bidimensionais), segue a estrutura dos dados homogêneos.
VETORES, STRINGS E MATRIZES
A forma mais simples de estruturar um conjunto de dados é por meio de vetores. Utilizamos os vetores quando temos muitas variáveis do mesmo tipo em um programa. Podemos imaginar o vetor como uma “fila” de variáveis do mesmo tipo e do mesmo nome que são identificadas por um número sequencial. Assim, podemos definir um vetor como um conjunto de variáveis exatamente do mesmo tipo que armazena, cada um associado a um número, que se refere à posição de armazenamento e é conhecido como índice.
Nessa figura, temos um vetor de sete posições preenchido com notas. Assim, por exemplo, no elemento de índice 4, temos como conteúdo a nota 2,5; num outro caso, o elemento de índice 6, temos a nota 9,5. Assim, no pseudocódigo, declaramos o vetor conforme segue.
Sintaxe:
· <nome>:vetor[inicio..fim] de tipo
A declaração do vetor ilustrado anteriormente fica:
Para fazermos uma atribuição de um elemento do vetor a uma variável, utilizamos a seguinte sintaxe:
· <variável> <- <nome> [índice]
Assim, se fizermos a atribuição NotaPedro<- notas [3], a variável NotaPedro passará a armazenar o valor 7,0.
Para fazermos a atribuição de um valor a um elemento do vetor, utilizamos a seguinte sintaxe:
· <nome> [índice] <- valor
Se fizermos a atribuição notas [4] <- 8,0, o vetor será:
Exemplo de aplicação:
Faça um programa que leia três temperaturas. Em seguida, calcule a temperatura média e a diferença de temperatura de cada uma delas em relação à média.
 Resolução:
 Caso fosse pedido um programa para calcular somente a temperatura média, teríamos apenas de fazer uma soma simples e dividir por 3.
O problema, contudo, pede para mostrar a diferença de cada temperatura em relação à média. Não temos como fazer a diferença em apenas um laço, pois a média somente será calculada após a digitação da última temperatura. Assim, já na primeira entrada, é impossível saber a temperatura média, e, se calcularmos a diferença após a última entrada, a informação da primeira temperatura já terá sido apagada. Para solucionarmos esse problema, precisamos usar o vetor, pois dessa forma temos como armazenar e recuperar cada uma das temperaturas dadas como entrada.
Uma vez calculada a média, poderemos calcular a diferença de cada temperatura com relação à média.
O pseudocódigo inteiro será:
VETORES EM C
Definimos um vetor em C da seguinte forma:
OBS: devemos tomar cuidado, pois o índice do vetor na linguagem C sempre se inicia em zero.
Assim, na declaração anterior, os elementos vão de v[0] até v[9].
Outra característica é que os vetores também podem ser inicializados na declaração:
Assim, o programa aloca, automaticamente, cinco espaços inteiros na memória.
Traduzindo o programa que lê três temperaturas e mostra a diferença de cada uma delas em relação à média:
Executando o programa, temos:
MATRIZES
Matrizes são vetores multidimensionais; os mais comuns são os bidimensionais. Assim, a matriz bidimensional é uma estrutura de dados que necessita de um índice para referenciar a linha e o outro para referenciar a coluna e localizar o elemento da informação.
Sintaxe:
<nome>:matriz[inicio..fim] [inicio..fim] de tipo
A declaração da matriz ilustrada é:
Para fazermos uma atribuição de um elemento da matriz a uma variável, utilizamos a seguinte sintaxe:
<variável> <- <nome> [índice] [índice]
Assim, se fizermos a atribuição Aluno <- notas [1] [2], a variável Aluno1 passará a armazenar o valor 7,0.
Para fazermos a atribuição de um valor a um elemento da matriz, utilizamos a seguinte sintaxe:
<nome> [índice] [índice] <- valor
Se fizermos a atribuição notas [3] [4] <-8,0:
MATRIZES EM C
Na linguagem C, podem ser criadas matrizes bidimensionais. Assim, para declararmos uma matriz de valores reais com três linhas e quatro colunas, fazemos:
Ao declararmos a matriz, o C reserva um espaço de memória para armazenar os 12 elementos da matriz, de maneira contínua, organizados linha a linha. Podemos então preencher a matriz na declaração:
Como a linguagem C ignora os caracteres de quebra de linha, para ficar mais fácil de visualizar durantea programação, podemos escrever da seguinte forma:
Outra maneira que a linguagem C permite é declararmos sequencialmente:
Em razão da particularidade da administração da memória, também podemos escrever da seguinte forma:
CADEIAS DE CARACTERES EM C (STRINGS)
As cadeias de caracteres em C (strings) são representadas por vetores do tipo char terminadas, obrigatoriamente, pelo caractere nulo (‘\0’). Sempre que ocorrer o armazenamento de uma cadeia, será necessário reservar um elemento adicional para o caractere de fim da cadeia. Todas as funções que manipulam strings (dos quais veremos alguns) recebem como parâmetro um vetor de char e processam caractere por caractere, até encontrarem o caractere nulo, que sinaliza o final da cadeia.
Para imprimirmos uma cadeia pela função printf, é necessário o especificador de formato %s. A função, na verdade, recebe um vetor de char e imprime elemento por elemento, até encontrar o caractere nulo (‘\0’).
O exemplo a seguir ilustra a representação de uma string. Como queremos representar a palavra Unip, composta por quatro caracteres, declaramos um vetor com dimensão 5 (um elemento adicional para armazenarmos o caractere nulo no final da cadeia). O código preenche os elementos do vetor, incluindo o caractere ‘\0’, e imprime a palavra na tela.
Ao executarmos, obtemos o seguinte resultado:
Se o ‘\0’ não fosse colocado, a função printf não encontraria o fim da cadeia, e o programa mostraria os caracteres que eventualmente restam na memória até encontrar um ‘\0’.
CARACTERES EM C
A linguagem C não oferece especialmente um tipo caractere. Os caracteres são representados por números inteiros que são convertidos em caracteres no momento da exibição. O tipo char armazena valores inteiros do tamanho de 1 byte, 8 bits, podendo então representar valores que variam de -128 a 127.
A diferença entre caracteres e inteiros, em C, acontece apenas no tratamento destes. Assim, podemos imprimir um mesmo valor de duas formas diferentes, desde que os formatos sejam diferentes.
Por exemplo:
Resulta em:
Como o número 97 corresponde ao caractere a, o printf, ao mostrar na tela a variável c no formato %d, exibe o conteúdo numérico, pois o formato é de número inteiro, e, para a letra a, quando encontra o formato %c, exibe o caractere correspondente ao número 97.
MANIPULAÇÃO DE STRINGS
A linguagem C, para manipular strings e caracteres, fornece algumas bibliotecas. Essas bibliotecas dão algumas funções extras, além do scanf e do printf, para entrada e saída de caracteres e cadeias.
· Função putchar(): a função putchar() (put character) da biblioteca stdio.h imprime um caractere na saída-padrão (em geral, o monitor de vídeo).]
· Função getchar(): a função getchar() (get character) da biblioteca stdio.h lê um caractere do teclado, ou arquivo. Se ocorrer um erro ou uma condição de “fim de arquivo” durante a leitura, a função retornará o valor da constante simbólica end of file (EOF) definida na biblioteca stdio.h, permitindo facilmente a detecção de finais de arquivos. Essa função não retorna valores até que o caractere de controle enter (\n) seja lido. Exemplo: o programa a seguir mostra o uso das funções getchar() e putchar() em um programa que lê caracteres do teclado e os reimprime convertidos para maiúsculos.
· Funções getch() e getche(): A função getch() (get character) da biblioteca stdio.h lê os códigos de teclado. Isso envolve não só os caracteres ASCII, mas também as teclas de comandos ([enter], [delete], [Page Up], [F1] etc.) ou combinações de teclas ([Alt] + [A], [Shift] + [F1], [Ctrl] + [Page Down] etc.). A função getch() aguarda que uma tecla, ou combinação de teclas, seja pressionada, recebe do teclado o código correspondente e retorna esse valor. A função getche() (get character and echoes), além de receber o código, ecoa, no dispositivo de saída, o caractere correspondente. Quando nos códigos especiais são pressionadas certas teclas, ou combinações destas, que não são caracteres ASCII, o teclado envia ao buffer de entrada do computador dois códigos, sendo o primeiro sempre 0, seguido do código correspondente. Por exemplo, se a tecla F1 for pressionada, os valores 0 e 59 serão armazenados, e a função deverá ser chamada duas vezes para ler os dois códigos. Exemplo: um programa para a leitura de teclado que usa a função getch() para reconhecer teclas e combinações de teclas.
Ao digitarmos Ctrl-Alt-x e depois o caractere u e a tecla Esc, teremos o seguinte resultado:
· Função puts (): a função puts () (put string) da biblioteca stdio.h mostra uma string na tela acrescentando um enter (\n) ao final.
· Função gets(): a função gets()(get string) da biblioteca stdio.h lê uma string do teclado até o operador digitar o enter. Exemplo:
Testando com o exemplo Joaquim Santos, temos:
· Função strlen(): a função strlen() (string length), da biblioteca string.h, retorna o tamanho de uma cadeia. Conta a quantidade de caracteres até encontrar um nulo (\0) e não o conta. Exemplo: o programa retorna o tamanho da cadeia digitada.
A biblioteca usada é string.h. O resultado é:
· Função strcat(): a função strcat() (string concatenate), da biblioteca string.h, tem duas cadeias concatenadas (unidas uma após a outra). A função recebe duas strings como argumento e copia a segunda string no final da primeira. Exemplo: fazer um programa que junte duas cadeias.
· Função strcpy: O strcpy (string copy) é uma função da biblioteca string.h que copia uma string em uma variável. Ao contrário da função strcat, que faz a concatenação, essa função sobrescreve a cadeia caso esta já tenha um valor armazenado. Exemplo:
Nesse programa, a saída é dada por duas variáveis, e nenhuma delas foi a variável em que foi dada a entrada. O resultado do programa é:
· Função stcmp(): na função strcmp() (string compare), da biblioteca string.h, duas cadeias são comparadas. A comparação é feita caractere a caractere, até encontrar a primeira diferença entre eles; conforme a diferença, a função devolve um valor diferente, usando o seguinte critério:
- < 0, se cadeia1 < cadeia2;
- = 0, se cadeia1 < cadeia2;
- > 0, se cadeia1 < cadeia2.
Exemplo de aplicação:
Executar o programa a seguir:
DADOS HETEROGÊNEOS
Uma estrutura de dados é chamada de heterogênea quando envolve a utilização de mais de um tipo básico de dado, que é chamado de registro, em certos casos.
Assim como existem tipos predefinidos, como inteiro, real, cadeia e lógico, podemos dizer que, ao usarmos registros, estamos criando um novo tipo de dado. Assim, antes da declaração das variáveis, temos de definir os novos tipos que estão sendo criados para depois serem declarados como variáveis.
Sintaxe:
Onde:
· Identificador: representa o nome associado ao tipo registro construído;
· Campo1, campo2, campoN: são os nomes associados a cada campo do registro.
Da mesma forma que na declaração de vetores e matrizes, primeiro, devemos criar um tipo, para então declararmos as variáveis desse tipo.
Para atribuirmos ou recebermos valores, referimo-nos às variáveis na forma:
variável.campo
Por exemplo:
ESTRUTURA EM C
Em C, o tipo registro é conhecido como estrutura. Uma estrutura em C serve basicamente para agrupar diversas variáveis em um único contexto. A sintaxe para a definição de uma estrutura é mostrada a seguir:
Exemplo de aplicação:
Definir um tipo que represente um ponto no plano cartesiano:
A estrutura, uma vez criada, passa a ser utilizável dentro do programa, atuando como variáveis.
Utilizando a estrutura do ponto, fazer um triângulo com os pontos p1 = (0,0), p2 = (1,1) e p3 = (1,0) no plano cartesiano.
OBS: Em razão da forma pela qual a linguagem C processa o programa, a criação e a declaração de um registro e de suas variáveis podem ser feitas da seguinte maneira:
TIPO UNIÃO
As uniões são usadas quando armazenamos valores de tipos diferentes compartilhando um mesmo espaço de memória.
Assim como na declaração da estrutura, a declaração da união não declara nenhuma variável, apenas define o tipo união. Assim, uma vez definida a união, é necessário declararmosvariáveis do tipo união:
Na variável v, os campos i e c usam o mesmo espaço de memória.
O operador ponto (.) é usado para acessar diretamente a variável, e o operador seta (->), para acessá-los por meio de um ponteiro.
MODULARIZAÇÃO
Quando temos um programa muito grande, muitas vezes, torna-se difícil acompanharmos a lógica ali empregada. Com o uso das funções, podemos dividir grandes tarefas de computação em tarefas menores. A criação de funções evita a repetição de código. Quando um procedimento é repetido diversas vezes, deve ser transformado numa função, que será chamada diversas vezes. Um programa bem-estruturado deve ser pensado no que se refere a funções fora do corpo principal do programa. Tal processo se chama modularização.
Imaginemos um programa que repete várias vezes uma sequência que limpa a tela, desenha um logotipo nessa tela e apresenta o nome do usuário em um canto da mesma tela durante a execução de um programa.
Como existe constante repetição, podemos fazer o processo de modularização, criando um pequeno programa com a sequência de limpar a tela, desenhar as imagens e mostrar o nome do usuário, e chama-lo do programa principal.
Dessa forma, o programa principal fica mais limpo, pois as instruções repetitivas e desnecessárias estão no procedimento.
FUNÇÕES E PROCEDIMENTOS
A diferença entre uma função e um procedimento é o fato de a função retornar um valor, e o procedimento, não.
No pseudocódigo o procedimento é declarado antes do início do programa principal.
Veja o algoritmo a seguir, que utiliza um procedimento que calcula a área de um triângulo:
É importante a declaração do tipo de valor que uma função retorna. Uma função não pode ora retorna um número, ora retornar uma cadeia. Em virtude desse fato, é obrigatório declarar no cabeçalho da função qual o tipo que esta retorna.
FUNÇÕES E PROCEDIMENTOS EM C
Os programas em C usualmente são montados com a reunião de várias pequenas funções, em vez de poucas de maior tamanho. Na linguagem C, tudo é feito por meio de funções e de suas bibliotecas. Já vínhamos utilizando algumas, como as da biblioteca stdlib.h, para entrada e saída de dados.
Sintaxe da função em C:
O <tipo de retorno> pode ser qualquer um, até os criados por meio do struct. Um caso particular é o do tipo void (nulo). Isso significa que a função não retornará nenhum valor, ou seja, é um procedimento.
Durante a programação, a execução sempre começa no main(). Na verdade, o próprio main() é uma função. O tipo, até agora, é void, e o parâmetro é vazio. Os parâmetros da função main são aqueles passados quando um programa é executado na linha de comando e alguns valores são digitados após o nome. Dessa maneira, é feita a interação do ambiente operacional e do programa.
Exemplo de aplicação:
Traduzir o programa de combinação simples.
VARIÁVEIS LOCAIS E VARIÁVEIS GLOBAIS
Uma variável criada dentro de uma função existe quando esta é executada, e dentro do espaço de memória dessa função. Assim, uma variável muito utilizada, como o i usado no controle de laços, usará um outro espaço se houver uma outra variável com o mesmo nome em outra função. Dessa forma, a variável i de uma função A é independente de uma variável i da uma função B, pois estão em locais diferentes, e localmente dentro das funções. Portanto, as varáveis declaradas dentro das funções se chamam variáveis locais.
Caso seja necessário às variáveis que várias funções as atualizem sempre, armazenando um valor global independentemente da função que está sendo executada, essas variáveis devem ser declaradas fora das funções e antes da primeira função que aparece na programação. Tais variáveis são as chamadas variáveis globais.
Assim:
Nesse exemplo, as variáveis a, b, c, d, e, f são globais, podendo ser utilizadas dentro das funções, como acontece com a variável a na função A e com o d e o e na função B. As variáveis n, x e y só valem dentro das suas respectivas funções; assim, o x da função A é totalmente independente do x da função B.
ALOCAÇÃO DINÂMICA DA MEMÓRIA
Ao declarar um vetor, para dimensioná-lo, era necessário saber de antemão quantos elementos iriam compô-lo. Tínhamos de prever o número máximo de elementos no vetor durante o processo da codificação. O pré-dimensionamento do vetor é um fator que limita a programação. Uma solução seria superdimensionar o vetor para tentar contornar essa falta de elementos livres durante a execução do programa, mas isso acarreta um desperdício de memória, o que é inaceitável em diversas aplicações, como aplicativos portáteis, em que sempre estamos sujeitos a ter falta de memória.
A linguagem C oferece meios de utilizar e racionalizar o uso da memória durante a execução do programa, ou seja, podemos alocar memória dinamicamente. Esse recurso permite ao programa alocar elementos ou registros dinamicamente, sem desperdício de memória.
O USO DA MEMÓRIA
Basicamente, existem três maneiras de reservarmos espaço de memória para o armazenamento de informações, sem o rigor técnico.
A primeira maneira é por meio do uso de variáveis globais (e estáticas). Nessa categoria de variáveis, o espaço reservado para uma variável existirá enquanto o programa estiver sendo executado.
A segunda maneira é usando variáveis locais. Nessa categoria, o espaço na memória existe apenas no período em que a função que declarou a variável está sendo executada, sendo liberado assim que a execução da função terminar. Como consequência, a função que chama não pode fazer referência ao espaço local da função chamada. As variáveis globais ou locais podem ser simples ou vetores. Para os vetores é necessário informar o número máximo de elementos, caso contrário o compilador não terá a informação sobre o tamanho do espaço a ser reservado.
A terceira maneira de reservar a memória é solicitar ao programa que aloque dinamicamente um espaço na memória durante sua execução. Esse espaço permanece reservado até que seja liberado explicitamente pelo programa, por meio de um comando específico.
PONTEIROS DE VARIÁVEIS
Pelo que vimos até agora, cada vez que uma variável é declarada, um espaço é alocado na memória para armazenar valores. Tecnicamente, é feito mais do que a simples reserva. O programa tem uma tabela, em que armazena o nome da variável, o endereço e o tipo de valor que será armazenado. Assim, ao escrevermos int a;, o programa reserva um espaço, normalmente de 4 bytes, por ser inteiro, no primeiro espaço livre da memória que encontrar. Em seguida, cria uma linha em uma tabela, na qual armazena o endereço e o tipo associado à variável criada nesse momento.
Em muitas ocasiões, seria interessante poder acessar o conteúdo de um local da memória de outras maneiras que não fossem pelo nome ou pelo endereço de memória.
A linguagem C tem uma maneira especial de uma variável armazenar endereços. Essa variável se chama ponteiro. A declaração de uma variável é feita da seguinte forma:
Por exemplo:
O programa reserva um espaço na memória para uma variável chamada p, que irá guardar um endereço, e esse endereço armazenado conterá uma informação do tipo inteiro. O símbolo * identifica que uma variável é do tipo ponteiro.
Para acessar os endereços de memória, a linguagem oferece dois operadores unários:
· & (“endereço de”): aplicado a variáveis, resulta no endereço da posição da memória reservada para a variável.
· * (“conteúdo de”): aplicado a variáveis do tipo ponteiro, acessa o conteúdo do endereço de memória armazenado pela variável ponteiro.
PASSAGEM DE VALORES POR VALOR E POR REFERÊNCIA
Quando estudamos funções vimos que, quando passamos informações para dentro de uma função, fazemos isso por meio de parâmetros. Também foi dito que uma função é aquela que devolve um e apenas um valor, ou seja, não devolve mais de um valor. O uso de ponteiros amplia a possibilidade de utilização dos parâmetros e solução de problemas de retornos múltiplos.
Dizemos que há uma passagem de parâmetros por valor quando conteúdos (e não endereços) são passados para as funções.
No exemplo a seguir, os valores de a e b são passados paraa função troca.
O resultado de a é 7 e o de b é 5, pois efetivamente as variáveis a e b são locais da função main ().
Quando os parâmetros passados são endereçados, dizemos que foram passados por referências, como no exemplo a seguir:
Apesar de os programas serem praticamente idênticos, o resultado é bem diferente, pois o mecanismo de trabalho foi bem diverso.
PASSAGEM DE VETORES PARA FUNÇÕES
Como dito, a linguagem C não passa vetores como parâmetros de função; assim, a maneira que temos para fazê-lo é passando o endereço da primeira posição do vetor. Dessa forma, para receber um vetor, devemos colocar uma declaração do mesmo tipo do vetor com a indicação de que é um ponteiro (usando o *).
Exemplo de aplicação
Dado o programa a seguir:
Na função main() é criado o vetor inteiro a[], que será passado como parâmetro para a função incvetor(). Assim, a função recebe o endereço do vetor a pela declaração int * v. Nesse caso, o vetor é chamado de a na função main() e, dentro da função incvetor(), é tratado como v. Como ambos têm o mesmo endereço, ambos se referem ao mesmo espaço de memória.
 O resultado desse programa é:
O programa passa como parâmetros um número e um vetor; este tem como elementos os valores {1, 3, 5}. A função recebe o endereço do vetor, refere-se a ele como v e acrescenta 1 a cada elemento; assim, o vetor é alterado para {2, 4, 6}
FUNÇÕES DA BIBLIOTECA-PADRÃO
Muitas vezes, o uso de vetores e matrizes fica limitado pela necessidade de sabermos antecipadamente a quantidade de elementos que serão necessários. O interessante seria termos condições de criar e destruir elementos sem a limitação (apenas da máquina, e não da lógica), conforme forem surgindo as necessidades de uso.
A biblioteca stdlib.h possui algumas funções que nos permitem criar e trabalhar dinamicamente, ou seja, durante a execução de um certo trecho do programa. Para isso, precisamos entender algumas funções e utilizar os conhecimentos do uso da memória que vimos até agora.
A melhor forma de usarmos todas as funções necessárias a partir deste momento do curso é mostrando que, fazendo manualmente, o trecho:
é equivalente a simplesmente declararmos: 
RECURSIVIDADE
Vimos que os vetores são limitados porque, desde o começo, precisamos saber a sua dimensão, e tivemos como solução o uso da alocação dinâmica da memória, para casos em que, a cada execução do programa, as suas dimensões podem mudar. Agora existem casos em que não só a memória, mas também o próprio programa tem de se adaptar a uma situação diferente a cada momento. Não é prático alterar o programa antes de cada execução. Para solucionar alguns desses problemas, podemos utilizar a recursividade. Existem algumas situações que só podem ser contornadas por meio dela.
A recursividade é a possibilidade de uma função se chamar, ou, então, voltar a ser chamada após a execução de funções que ela mesma chamou. Isso quer dizer que, a cada chamada, o programa abre um novo espaço na memória para a sua execução. A cada chamada recursiva, é guardada uma cópia dos parâmetros, de modo que não percamos os valores dos parâmetros das chamadas anteriores. Em princípio, enquanto houver memória para a recursividade, a função poderá ser reutilizada.
As funções recursivas tem duas características importantes:
· Ponto de parada: geralmente, um limite superior ou inferior da regra geral;
· Regra geral: reduz a resolução do problema por meio da invocação recursiva de casos menores, resolvidos mediante a resolução de casos ainda menores, e assim sucessivamente, até atingir o ponto de parada, que finaliza o método.
As funções que não são recursivas são chamadas de iterativas.
Exemplo de aplicação:
Multiplicação de inteiro:
A função se chama sucessivamente e, a cada chama, o valor do parâmetro y decresce, até chegar ao ponto de parada, (y==1), e passa a ter retornos sucessivos, até a primeira chamada.
ESTRUTURA UNIDIMENSIONAL, LISTAS
A estrutura de dados mais simples é a lista linear, uma cadeia de informações, todas com a mesma estrutura, mas correlacionadas. Cada uma dessas estruturas é chamada de nó, e, em alguns casos particulares, registro.
Na manipulação de listas, precisamos de três operações fundamentais:
· Inclusão;
· Busca;
· Remoção.
LISTA LIGADAS
No trabalho de sistemas computacionais, o conceito básico para as estruturas unidimensionais é a lista ligada. Uma lista pode estar na memória ou no disco. Veremos como manipular essas listas na linguagem C.
O conceito de registro corresponde ao armário; em cada registro existe uma informação endereçando para o registro seguinte, que é a chave. Um armário não precisa ser contíguo a outro, assim como um registro na memória RAM não precisa ser contíguo a outro.
Conceitualmente, uma lista ligada é um conjunto linear de nós, que segue unidirecionalmente. Cada nó é um conjunto de dados mais um ponteiro indicando o endereço do elemento seguinte.
Essa sequência pode ter um número indeterminado de elementos, e o primeiro elemento deve ser apontado por uma variável ponteiro.
Um nó pode conter qualquer tipo de informação, como dados, acrescido de um ponteiro.
Na linguagem C, o nó é um registro feito por meio da estrutura heterogênea struct.
Na estrutura no temos a declaração normal de nome e idade, bem como o ponteiro próximo, que tem a própria estrutura no, pois apontará para um novo nó que possui a mesma estrutura, uma estrutura autorreferenciada.
Tanto o nome quanto a idade são dados como exemplos e podem ser outros tipos de informações apropriados para vários propósitos, como cadastro de bibliotecas, estoque de materiais, lista de alunos etc.
FUNÇÃO DE INICIALIZAÇÃO
Toda lista, ou outras estruturas, deve ser inicializada. No caso da lista ligada, devemos criar uma lista vazia, sem nenhum nó. A própria lista é representada pelo ponteiro apontando para o primeiro elemento, e uma lista vazia é representada pelo ponteiro NULL. A função tem como valor de retorno a lista vazia iniciada, isto é, o valor de retorno é NULL.
A função de inicialização é:
Para executar a função, no main, teremos:
Quanto à instrução No* lista, cria-se uma variável ponteiro do tipo No chamada lista. Depois, essa variável recebe o valor NULL, pois a função inicia( ) retorna apenas o nulo.
FUNÇÃO DE INSERÇÃO
Com a lista vazia, estamos em condições de inserir os nós componentes da lista ligada. Cada novo elemento inserido na lista é alocado dinamicamente na memória e encadeado na lista existente. A função de inserção insere o novo elemento no início da lista.
A função de inserção aloca dinamicamente na memória o espaço para armazenar o novo nó da lista, armazena a informação no novo nó e o faz apontar para o próximo nó, aquele que era o primeiro da lista. Em seguida, a função retorna o novo endereço que representa a lista. A figura a seguir ilustra a operação de inserção de um novo elemento no início da lista:
A função main() chama a função para inserir a informação 23 na lista:
Analisando passo a passo a função, ao ser chamada pelo main( ) pela instrução lista = insere(lista, 23);, como no cabeçalho da função, temos:
A função irá retornar um endereço, que conterá um tipo No e receberá um endereço também do tipo No, que será recebido na variável lista, e um inteiro, que será recebido na variável num.
O parâmetro lista recebe os valores de lista (NULL) e o valor 23, que é atribuído à variável num. Alocaremos um espaço na memória para criar um nó do tipo No. Uma vez criado o novo nó, ele está em condições de receber os dados.
Feita a inserção, a função retorna o endereço do nó criado:
Como a variável novo no está no endereço 109, o seu conteúdo é 111, então esse endereço será devolvido ao programa principal, e o espaço utilizado pela função insere será desocupado.
Para vermos a criação de um novo nó que não o primeiro, será incluído mais um elemento na lista:
A função insere cria na memória as variáveis lista e num nos endereços que encontra livre, ou seja, novamente, em 103 e 105. São passados os valores 111, que é o atual endereço da lista, e 45, como informação.O novo nó é criado no espaço livre que o programa encontra.
A função malloc procura o primeiro espaço livre e aloca a quantidade de bytes determinado pelo sizeof do tipo No. Esse espaço é formatado conforme a estrutura do no pelo cast (No *), e o endereço, armazenado em novo no.
O novo nó está em condições de receber os dados.
Com a nova inserção, a função retorna o endereço do nó criado:
Nesse ponto, a nossa lista está assim:
Continuando a fazer outras operações de inclusão:
Nesse ponto, a nossa lista está assim:
FUNÇÃO DE REMOÇÃO
Uma vez implementada uma função de inserção, outra função importante é a remoção de um nó. A remoção deve ser feita sem que a lista perca a sua integridade, continuando a senr uma sequência em que cada elemento aponte para o nó seguinte. A função usa como entrada a lista e o valor do elemento que desejamos retirar, devendo retornar o valor atualizado da lista. A necessidade de retornar o endereço atualizado ocorre porque o nó a ser removido pode ser o primeiro da sequência e, se não for atualizado, a lista perderá a informação inicial.
A primeira situação acontece quando o nó a ser removido é o primeiro da lista. Nesse caso, antes da remoção, deve-se preservar o endereço que esse nó está apontando, pois será o endereço da lista.
A segunda situação ocorre quando o nó a ser removido está dentro da sequência. Nesse caso, dois nós são afetados. Antes da remoção, o endereço apontado pelo nó é preservado, e, após a remoção, o nó anterior da sequência recebe o endereço que estava preservado, passando assim a apontar para o nó que anteriormente era apontado pelo nó removido.
A função retira é bem mais complexa que a inserção, pois deve, inicialmente, ter uma rotina para encontrar o nó a ser removido. Partindo do início da lista, um laço percorre sequencialmente a lista e, ao mesmo tempo, fica registrado o nó anterior para fazer a atualização do ponteiro. Uma vez localizada, devemos fazer a remoção, levando em conta as duas situações relatadas anteriormente, liberar o espaço desocupado e retornar a lista, independentemente de o elemento removido ter sido o primeiro ou o intermediário
Uma vez claro o conceito básico, analisemos a função de retirada.
A função main () chama a função de retirada passando como parâmetro a lista e o valor contido no nó que será removido.
Ao ser chamado, o cabeçalho inicia o processamento da função:
Não terminei de resumir pois acho que será desnecessário no momento para a prova pulei para:
PILHAS
Quando pratos estão empilhados, não conseguimos ter acesso aos pratos de baixo da pilha sem retirar os de cima. Da mesma forma, quando uma função chama outra função, e assim por diante, o retorno de cada uma delas acontece sempre na ordem inversa à que foram chamadas, ou a última chamada é a primeira a retornar. Este é o conceito de pilha: o último que entra na sequência é o primeiro a sair; daí ser conhecido como (Last In First Out – LIFO). Uma pilha é, portanto, uma lista linear em que as operações são sempre realizadas pelo topo.
Na pilha, devemos implementar duas operações básicas: a operação para empilhar um novo elemento, inserindo-o no topo, e a operação para desempilhar um elemento, removendo-o do topo. Uma referência muito utilizada para essas duas operações são os termos em inglês push (empilhar) e pop (desempilhar). Vamos imaginar uma pilha composta pelos elementos que foram empilhados na ordem A, B, C, D; assim, podemos representar:
Aplicando a operação push(E), a pilha fica:
Aplicando diversas operações, teremos:
Pulei mais coisas pois: desnecessário nesse momento.
ÁRVORE
As árvores são estruturas de dados multidimensionais que permitem a representação de hierarquias, ou a representação em vários níveis. Uma árvore é composta por um conjunto de nós, que podem ou não ter ramificações. Existe um nó denominado raiz, que pode ramificar-se (ou não) em subárvores, cujas raízes são ligadas diretamente a essa raiz, e assim sucessivamente. Esses nós-raízes das subárvores são ditos filhos do nó-pai que podem ter mais nós-filhos. Portanto, em razão dessa característica de comportamento igual entre nó-pai e nó-filho, uma estrutura de árvore pode ser trabalhada usando a recursividade. Nós com filhos são comumente chamados de nós internos, e nós que não têm filhos são chamados de folhas, ou nós externos. É tradicional desenhar as árvores com a raiz pra cima e as folhas pra baixo.
ÁRVORES BINÁRIAS
Uma árvore binária é um caso especial de árvore em que um pai, no máximo, dois filhos (zero, um ou dois). Assim, recursivamente, os filhos são pais que têm, no máximo, dois filhos.
O uso da árvore binária é o mais difundido, e muitas vezes a adotamos sem saber que a estamos utilizando. Quando efetuamos (5+3) x 2 + (9+5), montamos uma árvore binária da seguinte forma:
Onde as operações são os nós, e os números, as folhas. Assim, na árvore:
O nó A é raiz, que tem como subárvores ou ramificações, do lado esquerdo, o nó B, e, do lado direito, o nó C, que, por sua vez, temo como subárvores, do lado esquerdo, o nó D, e, do lado direito, o nó E. Como B, D e E não tem ramificações, são chamados de folhas.
Em uma árvore binária, o caminho percorrido para sair de um nó e chegar a outro sempre será único. Assim, a prioridade fundamental da árvore binária é que, da raiz até qualquer um dos seus nós, haverá somente um caminho. A quantidade de nós percorridos da raiz (sem conta-la) até a folha mais distante determina a altura da árvore. Uma árvore apenas com a raiz tem altura zero. A árvore da imagem anterior tem altura 2.
Numa árvore binária, quando um nó tem ramificações, cada uma delas recebe um nome. A ramificação esquerda receberá o nome de Subárvore Esquerda (SAE), e a ramificação direita será a Subárvore Direita (SAD).
Mesmo tendo duas informações iguais, uma árvore que tem uma informação na SAE e outra que tem a mesma informação na SAD são diferentes:
PERCURSO EM ÁRVORES BINÁRIAS
A posição da informação nas subárvores é importante, pois, muitas vezes, precisamos percorrer uma árvore pra buscar informação, ou mesmo para descrê-la. Ao percorrer uma árvore, precisamos ter um critério, pois não podemos tomar um caminho qualquer, sob o risco de passarmos e colhermos informação de um mesmo nó.
Dentro de uma árvore, o conceito de recursividade torna-se fundamental, pois, em árvores grandes, dificilmente teríamos duas subárvores iguais e, portanto, não podemos antever uma sequência fixa de operações.
Há três ordens de leitura principais, que veremos a seguir.
PERCURSO EM PRÉ-ORDEM OU PREFIXO (busca em profundidade)
O percurso em pré-ordem faz, recursivamente, a partir da raiz, o seguinte:
· Lê o nó;
· Vai para o SAE;
· Vai para o SAD.
Assim, dada a árvore:
Exemplo de árvore
Montamos as recursividades, N E D, Nós, SAE, SAD, e iniciamos da raiz:
Leitura do nó
Percurso: 5
Vai para E (esquerda), em direção ao próximo nó
Como caminhou para o nó esquerdo, ainda falta executar o D do primeiro nó;
Faz a leitura do nó seguinte
Percurso: 5 2
Segue para a esquerda
Lê o nó
Percurso: 5 2 1
Tenta ir para a esquerda, mas não é possível, pois não há SAE
A seguir, tenta ir para a direita, e também não é possível avançar
Como todas as funções foram executadas, retorna para onde foi chamado
No nó anterior, a operação faltante é ir para a direita
Faz a leitura do nó
O percurso fica: 5 2 1 3
Nó sem SAE
Observe que esse nó não tem SAE, então vai para a SAD
Faz a leitura do nó
Percurso: 5 2 1 3 4
Como não tem pra onde seguir, retorna para o nó que o chamou
Novamente, todas as operações estão feitas, então retorna ao nó que o chamou
Nó com todas as operações executadas
No nó, também encontra todas as operações feitas, então retorna ao que chamou. Encontra então uma operação que ainda está em aberto, que é para ir para o SAD.
Indo para o nó à direita, faz a leitura
Percurso: 5 2 1 3 4 7
Vai para a esquerda e faz a leitura
Percurso: 5 2 1 3 4 7 6
Como não tem ramificações, retorna ao nó que chamou
Encontrado a operação para a direita, segue nesse ramo e faz a leiturado nó
Percurso: 5 2 1 3 4 7 6 8
Faz a leitura, ficando:
Retorna à raiz e não encontra mais operações em aberto
Assim, o percurso está completo, com o resultado: 5 2 1 3 4 7 6 8
PERCURSO EM ORDEM OU INFIXO (ordem simétrica)
O percurso em ordem faz, recursivamente, a partir da raiz, o seguinte:
· Vai para o SAE;
· Lê o nó;
· Vai para o SAD.
Fazendo o percurso na mesma árvore:
Árvore para o percurso esquerda, nó, direita
Seguidamente, a recursividade caminha para a esquerda
Chegando à folha, lê o nó e retorna
Percurso: 1
Lê o nó seguinte e caminha para o ramo direito
Percurso: 1 2
Como não há ramificação à esquerda, lê o nó e caminha para a direita
Percurso: 1 2 3
O nó seguinte é uma folha, então lê e faz o caminho de volta
Percurso: 1 2 3 4 5
Como todas as chamas já estão efetuadas, volta para a raiz, lê a raiz e caminha para a direita
Percurso: 1 2 3 4 5
Caminha para a direita e depois para a esquerda
Como o nó é uma folha, lê o valor e retorna para o nó que o chamou
Percurso: 1 2 3 4 5 6
Lê o nó e segue para o ramo direito
Percurso: 1 2 3 4 5 6 7
Por se tratar de uma folha, lê o valor e retorna, completando o percurso
Percurso: 1 2 3 4 5 6 7 8
PERCURSO EM PÓS-ORDEM OU POSFIXO
O percurso em pós-ordem faz, recursivamente, a partir da raiz, o seguinte:
· Vai para a SAE;
· Vai para a SAD;
· Lê o nó.
Fazendo o percurso na mesma árvore>
Percurso esquerda, direita, leitura
O percurso se inicia como o infixo, caminhando para a esquerda
Como na folha não há ramo direito, lê o valor do nó e retorna
Percurso: 1
Retornando, segue para a direita. Como os próximos não têm a SAE, segue pela SAD
Lê o nó e retorna
Percurso: 1 4
Lê o nó e retorna
Percurso: 1 4 3
Lê o nó e retorna
Percurso: 1 4 3 2
Voltando para a raiz, o próximo passo é ir para a direita
No nó seguinte, vai para a esquerda
Chegando à folha, lê o valor e retorna
Percurso: 1 4 3 2 6
Segue para a direita e lê a folha
Percurso: 1 4 3 2 6 8
Retornando, a operação que falta é a leitura do nó; faz essa operação e retorna
Percurso: 1 4 3 6 8 7
Finalmente, a última operação faltante: a leitura do nó da raiz
Percurso: 1 4 3 2 6 8 7 5
ÁRVORES BINÁRIAS DE BUSCA
Uma árvore binária de busca ou árvore binária de pesquisa é uma estrutura de dados em que todos os nós da subárvore esquerda possuem valor inferior ao do nó-raiz e todos os nós da subárvore direita possuem um valor superior ao do nó-raiz. Dessa forma, a busca de um valor torna-se muito fácil, pois, a partir de simples comparações, podemos localizá-lo, com menos passos. Imagine, por exemplo, a sequência de entrada:
50 67 20 13 31 35 80 60 62 2 55 25
No caso de estrutura linear, teríamos:
Com a estrutura montada, na mesma sequência de entrada, em uma árvore, temos:
Nessa árvore, para ir da raiz até quaisquer dos nós, são necessários, no máximo, três “pulos”. Se em uma busca precisássemos localizar o valor 2, procurando sequencialmente, teríamos de dar nove “pulos”.
No caso da busca na árvore, sabendo que os valores menores estão na SAE, e os números maiores, na SAE, para procurar o número 2, partindo da raiz, como 2<50, procurando na SAE; 2<20, então buscamos na SAE; 2<13, procuramos na SAE; e localizamos.
Quantidade de passos para localizar o número 2 numa árvore binária de busca
Em três “pulos”, o número é localizado, enquanto na busca sequencial a quantidade de pulos depende do momento em que o número foi digitado: quanto mais tarde, mais demoraremos a localizá-lo. Dessa forma, os gerenciadores de bancos de dados utilizam essa técnica nos índices, utilizando a informação dos campos-chave para os nós, e a busca torna-se bem mais rápida.

Outros materiais