Baixe o app para aproveitar ainda mais
Prévia do material em texto
54 Unidade II Unidade II 3 ESTRUTURA DE DADOS Uma estrutura de dados é qualquer representação de dados e suas operações associadas. Mesmo um número inteiro ou um número de ponto flutuante armazenado no computador pode ser visto como uma estrutura de dados simples. Normalmente, uma estrutura de dados deve ser uma organização ou estruturação para uma coleta de dados e/ou itens. Uma lista classificada de números inteiros armazenados em uma matriz é um exemplo dessa estruturação. Assim, é possível realizar todas as operações em qualquer estrutura de dados. No entanto, o uso da estrutura (de dados) adequada pode fazer a diferença entre um programa em execução em alguns segundos e outro que requer muitos dias. 3.1 Dados homogêneos Uma estrutura de dados é um esquema para organizar dados na memória de um computador, uma maneira específica de armazenar e organizar dados em um computador a fim de que sejam usados com eficiência. Diferentes tipos de estruturas de dados são adequados para diferentes tipos de aplicativos, e, em alguns casos, são altamente especializados para realizar tarefas específicas. As estruturas de dados são usadas em quase todos os programas ou sistemas de software. Estruturas de dados específicas são ingredientes essenciais de muitos algoritmos eficientes e possibilitam o gerenciamento de enormes quantidades de dados, como grandes bancos de dados e serviços de indexação de internet. Ao selecionar uma estrutura de dados para resolver um problema, você deve seguir estas etapas: • analise seu problema para determinar as operações básicas que devem ser suportadas; • quantifique as restrições de recursos para cada operação; • selecione a estrutura de dados que melhor atenda a esses requisitos. A importância relativa dessas operações é abordada pelas três perguntas a seguir, que você deve ter em mente sempre que precisar escolher uma estrutura de dados. • Todos os itens de dados são inseridos na estrutura de dados no início ou são inserções intercaladas com outras operações? 55 ALGORITMOS • Os itens de dados podem ser excluídos? • Todos os itens de dados são processados em alguma ordem ou procuram itens de dados específicos? Algumas das estruturas de dados mais usadas incluem listas, matrizes, pilhas, filas, pilhas, árvores e gráficos. A maneira como os dados são organizados afeta o desempenho de um programa para a execução de tarefas diferentes. As estruturas de dados geralmente são baseadas na capacidade que um computador tem em buscar e armazenar os dados em qualquer lugar em sua memória, lugar esse especificado por um endereço – uma sequência de bits que pode ser ela mesma armazenada na memória e manipulada pelo programa. Os dados podem ser organizados de várias maneiras: o modelo lógico ou matemático de uma determinada organização de dados é chamado estrutura de dados. O modelo de dados pode ser rico o suficiente em estrutura para refletir o relacionamento real dos dados no mundo real. Por outro lado, a estrutura deve ser simples para executar o processo dos dados quando necessário. De acordo com Lakhwani (2013), a estrutura de dados pode ser classificada em dois tipos, linear ou não linear. • Linear: uma estrutura de dados é linear se seus elementos formarem uma sequência. Os elementos da estrutura de dados linear são representados por meio de locais de memória sequencial. Exemplo: matriz e lista de links. • Não linear: uma estrutura de dados é considerada não linear se seus elementos compuserem um relacionamento hierárquico entre elementos como árvores e gráficos. Todos os elementos atribuem a memória de forma aleatória e você pode buscar elementos de dados através do processo de acesso aleatório. Exemplo: árvores e árvores binárias. 3.1.1 Variáveis indexadas unidimensionais Nas palavras de Manzano: A matriz de uma dimensão é a forma mais simples de usar tabelas de valores com apenas uma coluna e várias linhas de dados. Essa estrutura de dados fica em uma única variável dimensionada com um determinado tamanho. A dimensão de uma matriz é formada por constantes inteiras e positivas. Os nomes dados a uma variável composta (matriz) seguem as mesmas regras dos nomes dados a variáveis simples e também ao comando var, com auxílio do comando conjunto na definição da matriz (MANZANO, 2019, p. 133). De acordo com Lakhwani (2013), o tipo mais simples de estrutura de dados é o vetor (ou uma matriz linear/unidimensional). Essa estrutura utiliza uma lista de um número finito (composta por n de elementos) de dados semelhantes referenciados, respectivamente, por um conjunto de 56 Unidade II n números consecutivos (geralmente 1, 2, 3… n). Se escolhermos o nome A para o vetor, então o elementos de A serão indicados pela notação de colchete: A [1], A [2], A [3] ... A [N] A[1]Nome da variável indexada (A) Índice (1) Figura 14 – Armazenamento de um vetor na memória Independentemente da notação, o número K em A [K] é chamado de subscrito e A [K] é chamado de variável subscrita. Uma variável indexada unidimensional é aquela que, a partir de um único nome e de um número (o índice), permite o armazenamento e a localização de um conjunto de dados. As variáveis indexadas unidimensionais também são conhecidas por arranjos unidimensionais ou, ainda, vetores (SOUZA et al., 2019). Na imagem a seguir, temos a estrutura de uma variável indexada que possui o nome de A, que representa quatro valores ao mesmo tempo. ... 98 99 100 -3 101 4 102 5 103 0 104 105 ... Memória A O vetor A possui os valores -3, 4, 5, 0 e está armazenado a partir da posição 100 da memória Figura 15 – Armazenamento de um vetor na memória Um vetor é uma estrutura que armazena vários dados de mesmo tipo, ao contrário das variáveis comuns, que só podem armazenar um valor de cada vez. Em programação, é das estruturas mais simples. Os elementos individuais são acessados por sua posição dentro do vetor. A posição é dada pelo chamado índice, que, em geral, utiliza uma sequência de números inteiros, que são acessados de forma rápida e eficiente (SOFFNER, 2013, p. 88). 57 ALGORITMOS O vetor é uma multivariável. Permite armazenar muitos números diferentes, valores de ponto flutuante, caracteres, cadeias ou qualquer tipo de variável em uma única unidade. Os vetores são declarados como outras variáveis, embora o nome da variável termine com um conjunto de colchetes: int RA_Aluno[3]; Nesse exemplo, o vetor RA_Aluno é declarado e pode conter três itens (é o que o “3” entre colchetes especifica). Os vetores também podem ser declarados e atribuídos ao mesmo tempo, como pode ser visto na sequência. float temperatura [] = {97.0, 98.2, 98.6, 99.1}; Esse vetor, denominado como temperatura, contém quatro valores de ponto flutuante. Cada item dentro do vetor pode ser referenciado de forma individual. Os itens são conhecidos como elementos. O primeiro elemento em um vetor é numerado pelo índice zero. Portanto, o elemento zero na matriz temperatura é número 97.0. Os valores também podem ser atribuídos aos vetores como às variáveis regulares. RA_Aluno [0] = 32; RA_Aluno [1] = 17; RA_Aluno [2] = 96; Essas três instruções atribuem os valores 32, 17 e 96 ao vetor RA_Aluno. Observe que o primeiro elemento é o índice zero (0). A seguir, temos um algoritmo em Portugol de um programa que realiza o cálculo da média aritmética dos elementos de um vetor. Início 1. C ← 1 2. Soma ← 0 3. Enquanto C <= 6 Faça 4. Ler(Q[C]) 5. Soma←Soma + Q[C] 6. C♂← C + 1 7. Fim Enquanto 8. Media ← Soma/6 9. Exibir(‘A média é:‘, Media) Fim 58 Unidade II Figura 16 – Algoritmo em Portugol para calcular a média aritmética dos elementos de um vetor De acordo com Manzano (2019), a leitura dos dados de uma matriz é processada passo a passo, um elemento por vez, por meio de um laço de repetição. A seguir, são apresentados o diagrama de blocos e a codificação em português estruturado da leitura das médias de cada um dos alunos, cálculo da média gerale a apresentação do resultado. SOMA ← 0 SOMA ← SOMA + MD[I] MÉDIA ← SOMA/8 MÉDIA Início Fim I ← 1, 8, 1 MD[I] Diagramação Codificação Figura 17 – Diagrama de blocos para leitura dos elementos de uma matriz do tipo vetor O processo de escrita dos dados de uma matriz é bastante parecido com o processo de leitura desses dados. Em seguida, são apresentados o diagrama de blocos e a codificação em português estruturado da escrita das médias individuais dos oito alunos antes de ser mostrado o resultado do cálculo da média geral. 59 ALGORITMOS SOMA ← 0 MÉDIA ← SOMA/8 SOMA ← SOMA + MD[I] Início Fim I ← 1, 8, 1 I ← 1, 8, 1 MD[I] Diagramação Codificação MD[I] MÉDIA Figura 18 – Diagrama de blocos para escrita dos elementos de uma matriz do tipo vetor Exemplo de aplicação Pesquise exemplos de algoritmos que utilizam a estrutura das variáveis indexadas unidimensionais. 60 Unidade II Saiba mais Uma boa recomendação de leitura são as obras de Manzano. Você pode ler, por exemplo, a que é indicada a seguir. MANZANO, J. A. N. G. Algoritmos: lógica para desenvolvimento de programação de computadores. São Paulo: Érica, 2019. Vejamos agora o que diz Manzano. Uma das operações mais importantes executadas com matrizes é, sem dúvida, a organização dos dados armazenados. A classificação numérica de dados pode ser efetuada na ordem crescente (do menor valor numérico para o maior) ou na ordem decrescente (do maior valor numérico para o menor). A classificação alfabética de dados pode ser efetuada na ordem ascendente (de “A” até “Z” ou de “a” até “z”) ou na ordem descendente (de “Z” até “A” ou de “z” até “a”). Primeiramente ocorre a ordenação dos caracteres alfabéticos maiúsculos e depois a ordenação dos caracteres minúsculos. A classificação alfanumérica de dados pode ser feita na ordem ascendente ou descendente. Esse tipo de classificação considera dados numéricos, alfabéticos e demais caracteres gráficos previstos na tabela ASCII. Para classificar dados em uma matriz de uma dimensão (ou mesmo matrizes com mais dimensões) não há necessidade de um programador desenvolver algoritmos próprios, pois já existe um conjunto de algoritmos para essa finalidade. Basta conhecer e escolher aquele que atenda mais adequadamente a uma necessidade específica. Entre as técnicas (os métodos) de programação para classificação de dados existentes, pode-se destacar as categorias: a. Classificação por inserção (método da inserção direta, método da inserção direta com busca binária, método dos incrementos decrescentes - shellsort). b. Classificação por troca (método da bolha - bubblesort, método da agitação - shakesort, método do pente - combsort, método de partição e troca - quicksort). c. Classificação por seleção (método da seleção direta, método da seleção em árvore - heapsort, método de seleção em árvore amarrada - threadedheapsort). 61 ALGORITMOS d. Classificação por distribuição de chaves (método de indexação direta - radixsort). e. Classificação por intercalação (método da intercalação simples - mergesort, método de intercalação de sequências naturais). f. Classificação por cálculo de endereços (método das listas de colisão, método da solução postergada das colisões) (MANZANO, 2019, p. 147-148, grifo do autor). A próxima imagem apresenta um programa que realiza a leitura de uma matriz dinâmica A com N elementos do tipo cadeia (caracter/texto) para representar os nomes de algumas pessoas e, em seguida, apresenta a lista de nomes que foram inseridos na matriz A. Início Fim I ← 1, N, 1 I ← 1, N, 1 A[I] N Diagramação Codificação A[I] Figura 19 – Diagrama de blocos para programa com matriz dinâmica 62 Unidade II Observação O vetor pode ser definido como uma variável composta homogênea unidimensional formada por uma sequência de variáveis do mesmo tipo de dados, com o mesmo identificador e alocadas sequencialmente na memória. 3.1.2 Matriz bidimencional Segundo Manzano: A utilização de matrizes em programação é bastante ampla, que vai desde o uso direto, quando o programador constrói a estrutura de dados e faz o seu controle operacional, até o uso indireto, quando o programador usa um sistema de gerenciamento de banco de dados para auxiliar a construção e controle das operações em tabelas de dados (MANZANO, 2019, p. 146). Até agora, o foco estava em como controlar algoritmos, examinando as construções e observando de que forma podemos utilizar as estruturas para controlar a ordem e as circunstâncias nas quais as etapas individuais de um algoritmo serão executadas. O motivo é que a escolha da estrutura de controle mais adequada é importante para projetar um algoritmo eficiente e eficaz. Entretanto, os algoritmos são projetados para manipular entradas na forma de dados e essas entradas precisam ser consideradas ao se projetar um algoritmo. Geralmente, os dados que serão processados por um algoritmo compreendem os itens que estão relacionados de alguma forma entre si, em vez de coleções arbitrárias de itens. Considere, por exemplo, os metadados que compõem um perfil de usuário, como nome, idade, endereço, função, número de contato etc. Esses itens são conectados logicamente entre si e não podem ser processados como uma coleção de itens não relacionados por um algoritmo; deve-se, portanto, processar como um registro em que cada registro compreende as informações sobre um usuário específico. Segundo Soffner (2013, p. 95): “Uma matriz é um vetor multidimensional. Alguns autores consideram ambas as expressões a mesma coisa, e o que muda é apenas o número de dimensões (como no termo em inglês, array, que vale para as duas coisas)”. Os dados devem ser organizados de maneira a capturar relações lógicas entre seus elementos, que juntamente com suas inter-relações formam uma estrutura de dados estruturados. O tipo mais comum de estrutura de dados é a sequência que compreende um conjunto de itens classificados de maneira que cada item (exceto o último na sequência) tem um sucessor e cada item (com exceção do primeiro na sequência) tem um antecessor. 63 ALGORITMOS Estes são alguns exemplos comuns de sequências de fácil compreensão: • um número apresentado como uma sequência de dígitos, por exemplo, 1512000 (1 é o primeiro, 0 é o último); • uma palavra apresentada como uma sequência de letras, por exemplo, sequência (“s” é o primeiro, “a” é o último). Observação A matriz pode ser definida como uma variável composta homogênea multidimensional, formada por variáveis, todas do mesmo tipo de dados, com o mesmo identificador. De acordo com Christodoulou et al. (2018), uma sequência é uma estrutura ideal para os itens que devem ser processados sequencialmente, um após o outro. A maneira mais comum de progredir através de uma sequência é por meio do uso de uma estrutura de repetição. A matriz é uma sequência de comprimento fixo em que cada elemento é identificado por sua posição na sequência, uma coleção indexada de elementos homogêneos. Uma sequência de matriz possui as seguintes propriedades: • todos os elementos da matriz são do mesmo tipo de dados (homogêneo); • em uma matriz composta por linhas e colunas, o tamanho de cada linha (número de colunas) é o mesmo para todas as linhas; • cada elemento de uma matriz é identificado por sua posição ao longo de cada dimensão (índice, por exemplo: num [1][4], num [4][1] etc.); • o tamanho de uma dimensão específica é constante. A matriz de duas dimensões é uma estrutura de dados com mais de uma coluna e mais de uma linha. A imagem a seguir apresenta uma matriz de uma dimensão e uma matriz de duas dimensões, além das diferenças entre as suas estruturas. 64 Unidade II Matriz A (1D) Índice Elemento 1 2 3 4 5 Tabela vertical de uma dimensão (uma coluna e várias linhas) Matriz A (2D) Índices 1 2 3 4 5 1 2 3 Elemento 4 5 Tabela de duas dimensões (várias colunas e várias linhas) Matriz A (1D) Índice 1 2 3 4 5 Elemento Tabela horizontalde uma dimensão (uma linha e várias colunas) Figura 20 – Matrizes de uma e duas dimensões Exemplo de aplicação Pesquise exemplos de algoritmos que utilizam a estrutura das matrizes bidimencionais. De acordo com Manzano (2019), a leitura dos dados de uma matriz de duas dimensões, assim como dos dados de matrizes de uma dimensão, é processada passo a passo por meio do comando leia seguido do nome da variável mais os seus índices. Na imagem a seguir, é possível observar o diagrama de blocos e a codificação em português estruturado da leitura de quatro notas bimestrais de oito alunos, sem considerar o cálculo da média. Início Fim I ← 1, 8, 1 Notas [I, J] J ← 1, 4, 1 Figura 21 – Diagrama de blocos para leitura dos elementos de uma matriz do tipo tabela 65 ALGORITMOS Esse exemplo apresenta a leitura das quatro notas (colunas) de oito alunos (linhas). Assim sendo, a tabela em questão armazena 32 elementos. Um detalhe é a utilização de duas variáveis para controlar os dois índices de posicionamento de dados na tabela. Nesse exemplo, a variável I continua com o mesmo efeito e a segunda variável, a J, controla a posição da coluna. Ao analisar o diagrama de blocos, tem-se a inicialização das variáveis I (linhas) e J (coluna) como o valor 1, ou seja, a leitura é feita na primeira linha da primeira coluna. Em seguida é iniciado em primeiro lugar o laço da variável I para controlar a posição de um elemento em relação às linhas, depois é iniciado o laço da variável J para controlar a posição do elemento em relação às colunas (MANZANO, 2019, p. 178). O processo de escrita de dados de uma matriz de duas dimensões é semelhante ao processo de leitura desses dados. Por exemplo, vamos imaginar que, após a leitura das notas dos oito alunos, houvesse a necessidade de apresentá-las. Acompanhe o diagrama de blocos e a codificação em português estruturado das quatro notas dos oito alunos. Início Fim I ← 1, 8, 1 Diagramação Codificação J ← 1, 4, 1 Notas [I, J] Figura 22 – Diagrama de blocos para escrita dos elementos de uma matriz do tipo tabela 3.2 Dados heterogêneos Vejamos o que diz Manzano: Um dos grandes problemas enfrentados pelos profissionais da área de desenvolvimento de software em microinformática é acumular funções. Nas áreas de minicomputadores e de computadores de grande porte essa incidência ocorre num nível muito pequeno e de forma esporádica (MANZANO, 2019, p. 190). 66 Unidade II E, agora, retomemos algumas palavras de Soffner: As estruturas permitem que armazenemos diversos tipos de dados diferentes na mesma estrutura, ao contrário dos vetores e matrizes que, como visto, trabalham apenas elementos do mesmo tipo. Isso aumenta em muito a capacidade de manipulação de dados do programa. As estruturas são chamadas por alguns autores de registros (SOFFNER, 2013, p. 111). 3.2.1 Tipo de dado derivado: estrutura de registro Sobre a estrutura de registro, diz Pressman: A estrutura de registro é um recurso que possibilita combinar vários dados de tipos diferentes (os quais serão chamados de campos) em uma mesma estrutura de dados. Por esta razão, esse tipo de estrutura de dados é considerado heterogêneo. De forma mais ampla, pode-se dizer que registro é uma coleção designada de dados que descreve um objeto de dados como sendo uma abstração de dados (PRESSMAN, 1995, p. 422). Um recurso preexistente em algumas linguagens de programação é a estrutura de registros para a composição da heterogeneidade de dados. A imagem a seguir apresenta um exemplo do layout básico de uma ficha de cadastro escolar de aluno, com os campos nome, primeira nota, segunda nota, terceira nota e quarta nota. 1ª notaSalaTurma Nome Escola de computação XPTO Cadastro escolar de aluno 2ª nota 3ª nota 4ª nota Figura 23 – Exemplo do layout de um registro com seus campos O tipo derivado preexistente registro deve ser declarado pelo comando tipo antes do comando var, uma vez que a variável que conterá a estrutura heterogênea de dados deve ser declarada com o tipo de dado registro definido no comando tipo. A declaração do tipo registro é uma tarefa delicada e precisa ser feita com cuidado, pois é a base para tabela ou tabelas heterogêneas que serão utilizadas no programa. Um erro na montagem de uma tabela heterogênea ocasiona grande problema no desenvolvimento do 67 ALGORITMOS programa. Além da criação do diagrama de blocos, que representa a linha de raciocínio utilizada pelo programador, é ideal fazer a documentação da estrutura dos dados a ser utilizada pelo programa (MANZANO, 2019, p. 192). A leitura de um registro é realizada com a instrução leia seguida do nome da variável do tipo registro e seu campo correspondente separado por um caractere “.” (ponto). A imagem a seguir apresenta o diagrama de blocos e o código em português estruturado. Início Fim Diagramação Codificação ALUNO.NOME ALUNO.TURMA ALUNO.NOTA2 ALUNO.SALA ALUNO.NOTA3 ALUNO.NOTA1 ALUNO.NOTA4 Figura 24 – Exemplo de leitura de um registro O processo de escrita de um registro é realizado com a instrução escreva de forma semelhante ao processo de leitura. Observe na imagem a seguir o diagrama de blocos e o código em português estruturado. 68 Unidade II Início Fim Diagramação Codificação ALUNO.NOME ALUNO.NOTA1 ALUNO.TURMA ALUNO.NOTA2 ALUNO.SALA ALUNO.NOTA3 ALUNO.NOTA4 Figura 25 – Exemplo de escrita de um registro Exemplo de aplicação Pesquise exemplos de algoritmos que utilizam a estrutura de registro. 3.2.2 Estrutura de matriz de registros Vejamos o que diz Manzano: Com as técnicas de programação [...], passou-se a ter muita mobilidade para trabalhar de forma mais adequada com diversos tipos de problema, principalmente aqueles que envolvem dados heterogêneos, facilitando a construção de programas que necessitam operar com uma estrutura de dados mais flexível. Os programas apresentados com registros só fizeram 69 ALGORITMOS menção à leitura e escrita de um único registro, mas não em relação a um número maior de registros. Assim sendo, introduz-se a matriz de registros que permite a construção de programas que fazem entrada, processamento e saída de diversos registros (MANZANO, 2019, p. 199). De acordo com Manzano (2019), a leitura dos elementos da matriz de registros deve ser feita com dois laços. Essa estrutura é bastante similar a uma matriz de duas dimensões. Observe a seguir o diagrama de blocos e o código correspondente em português estruturado. Início Fim I ← I, 8, 1 J ← 1, 4, 1 ALUNO[I].SALA ALUNO[I].NOTA[J] ALUNO[I].TURMA ALUNO[I].NOME Diagramação Codificação Figura 26 – Exemplo de leitura de um conjunto de registros O laço da variável I controla o número de alunos da turma, no caso oito, e o laço da variável J controla o número de notas, até quatro por aluno. Para cada movimentação de mais um na variável I, existem quatro movimentações na variável J. O processo de escrita dos elementos de uma matriz de registros é similar aos já estudados. Observe a seguir o diagrama de blocos e o código correspondente em português estruturado. 70 Unidade II ALUNO[I].NOME ALUNO[I].TURMA ALUNO[I].SALA ALUNO[I].NOTA[J] Início Fim I ← 1, 8, 1 J ← 1, 4, 1 Diagramação Codificação Figura 27 – Exemplo de escrita de um conjunto de registros Exemplo de aplicação Pesquise exemplos de algoritmos que utilizam a estrutura de matriz de registros. Lembrete Uma estrutura de dados é qualquer representação de dados e suas operações associadas. Mesmo um número inteiro ou um número de ponto flutuante armazenado no computador podem ser vistos como uma estrutura de dados simples. 4 LINGUAGEM C De acordo com Oram e Naik [ca. 2010], a linguagem de programação C foi desenvolvida nos Laboratórios Bell da AT&T, nos Estados Unidos, em 1972. Desenhada e escrita por Dennis Ritchie no final da década de 1970, a linguagem C começou a substituir os idiomas mais familiares da época, como PL / I, ALGOL etc. 71 ALGORITMOS As principais partesde sistemas operacionais populares como Windows, UNIX, Linux ainda estão escritas em C. Isso ocorre porque, ainda hoje, quando se trata de desempenho (velocidade de execução), nada supera essa linguagem. Além disso, se for necessário estender o sistema operacional para trabalhar com novos dispositivos, é necessário escrever programas de driver de dispositivo. Esses programas são escritos exclusivamente em C. Vejamos as características da linguagem e como conseguimos criar um programa em C. 4.1 Noções de ambiente de desenvolvimento de programas em C Existe uma analogia próxima entre aprender inglês e aprender a linguagem C. O método clássico para conseguir aprender um novo idioma, como é o caso do inglês, consiste em, a princípio, conhecer o alfabeto usado no idioma, aprender ao processo de combinação desse alfabeto para formar palavras que, por sua vez, são combinadas para formar frases, as quais, associadas, constituirão parágrafos. Aprender a programar na linguagem em C é semelhante, e talvez até mais fácil. Assim, em vez de aprender imediatamente como escrever programas, precisamos primeiro saber quais alfabetos, números e símbolos são usados em C, depois, como usá-los para a criação de constantes, variáveis e palavras-chave e, finalmente, como eles são combinados para formar uma instrução. Instruções seriam combinadas posteriormente para formar um programa. Portanto, um programa de computador é apenas uma coleção das instruções necessárias para resolver um problema. As operações básicas de um sistema de computador formam o que é conhecido como um conjunto de instruções do computador. Lembrete Em vez de aprender imediatamente como escrever programas, precisamos primeiro saber quais alfabetos, números e símbolos são usados em C, depois, como usá-los para a criação de constantes, variáveis e palavras-chave e, finalmente, como eles são combinados para formar uma instrução. 4.1.1 Linha de comentário Através da linha de comentário é possível incluir, no código fonte o objetivo do programa, explicações sobre os processos que estão sendo executados e outras informações. /*…………………………………*/ Figura 28 – Símbolo representando a linha de comentário 72 Unidade II A linha de comentários é usada para aumentar a legibilidade do programa. É útil para incluir no código as explicações, sendo geralmente usada também para auxiliar na documentação. A linha de comentário pode ser única ou múltipla, mas não deve ser aninhada; pode estar em qualquer lugar do programa, exceto dentro da constante ou no caractere da string constante. 4.1.2 Directiva do pré-processador (preprocessor directive) A indicação #include<stdio.h> orienta o compilador a incluir informações sobre a biblioteca padrão de entrada/saída. Também é usada em constante simbólica, como #define PI para representar o valor 3,14. O stdio.h (arquivo de cabeçalho de saída de entrada padrão) contém a definição e a declaração da função definida pelo sistema, como printf(), scanf(), pow() etc. Geralmente, a função printf() é usada para exibir informações para o usuário e a função scanf() é utilizada para ler (gravar) o valor digitado pelo usuário. 4.1.3 Declaração global (global declaration) Essa é a seção em que as variáveis são declaradas de forma global para que possam ser acessadas por todas as funções usadas no programa. E geralmente é declarada fora da função main(). A partir da função main(), o programa é iniciado e está dentro do par de chaves. Ela pode estar em qualquer lugar do programa, mas, na prática, geralmente é colocada logo na primeira posição do código. Sintaxe: main() { …….. …….. // restante do código …….. …….. } 4.1.4 A função main A função main() retorna um valor quando é declarado um tipo de dados, conforme pode ser visto no exemplo a seguir. int main () { return 0; } 73 ALGORITMOS A função principal não retorna nenhum valor quando é atribuído o indicador void (significa nulo/vazio), como pode ser visto a seguir. void main (void) ou void main() { printf (“Linguagem em C”); } Output / Saída: Linguagem em C A execução do programa começa com as chaves de abertura e termina com as chaves de fechamento. No final de cada linha, obrigatoriamente, devemos colocar o ponto e vírgula (que indica o encerramento de instrução). Veja um exemplo a seguir. Figura 29 – Primeiro programa c com declaração de retorno (imagem do programa Dev C++) 4.1.5 Etapas para compilar e executar os programas em C Um compilador é um programa de software que analisa um programa desenvolvido em uma determinada linguagem de computador e depois a converte em um formato adequado para execução em um sistema de computador específico. De acordo com Oram e Naik [ca. 2010], podemos relacionar algumas etapas em relação ao processo de criação e compilação de um programa utilizando a linguagem em C. Etapa 1 O programa a ser compilado é digitado primeiro em um arquivo no diretório do sistema de um computador. Existem várias convenções usadas para nomear arquivos, normalmente qualquer nome, desde que os dois últimos caracteres sejam “.c” ou arquivo com a extensão “.c”. Portanto, o nome do arquivo prog1.c pode ser um nome de arquivo válido para um programa em C. Um editor de texto geralmente é usado para inserir o programa C em um arquivo. Por exemplo, ao longo deste livro-texto, usaremos o programa Dev C++ (disponível de forma gratuita para download no seguinte link: https://sourceforge.net/projects/orwelldevcpp/). 74 Unidade II Figura 30 – Imagem do programa Dev C++ O programa que é inserido no arquivo é conhecido como programa de origem porque representa a forma original do programa expresso na língua C. Etapa 2 Depois que o programa de origem for inserido em um arquivo, devemos continuar com o processo de compilação. O processo de compilação é iniciado digitando um comando especial em um sistema. Quando esse comando é inserido, o nome do arquivo que contém o programa de origem também deve ser especificado. Na primeira etapa do processo de compilação, o compilador examina cada linha contida no programa de origem, verificando sua estrutura para garantir que esteja em conformidade com a sintaxe e a semântica da linguagem. Se algum erro for descoberto pelo compilador durante essa fase, ele será relatado ao usuário e o processo de compilação termina. Os erros devem ser corrigidos no programa de origem (com o uso de um editor) e o processo de compilação deve ser reiniciado. Os erros relatados durante essa fase de compilação podem ser classificados como: erro sintático (devido a uma expressão que possui parênteses colocados de forma equivocada) ou erro semântico (devido ao uso de uma variável que não foi “definida” anteriormente). 75 ALGORITMOS Etapa 3 Quando todos os erros sintáticos e semânticos forem removidos do diretório do programa, o compilador passará a traduzir cada instrução do programa em um formato “inferior” equivalente ao programa em uma linguagem de máquina (assembly). Etapa 4 Após a tradução do programa, a próxima etapa na compilação é o processo de traduzir as instruções da linguagem assembly em máquinas reais. O assembler pega cada declaração da linguagem assembly e a converte em um formato binário conhecido como código de objeto, que é gravado em outro arquivo no sistema. Etapa 5 Após o programa ser traduzido em código de objeto, ele está pronto para ser vinculado. O objetivo da fase de vinculação é obter o programa em um formato final para execução no computador. Se o programa usar outros programas que foram anteriormente processados pelo compilador, tais programas serão vinculados nessa etapa. Os programas usados na biblioteca de programas do sistema também são pesquisados e vinculados com o programa objeto durante essa fase. O processo de compilação e vinculação de um programa geralmente é chamado de construção. O arquivo final vinculado, que está em um formato de código de objeto executável, é armazenado em outro arquivo no sistema, prontopara ser executado. Etapa 6 Quando o programa é executado, cada uma das instruções do programa é executada de forma sequencial. Se o programa solicitar dados do usuário, conhecido como entrada, o programa suspende temporariamente sua execução para que a entrada possa ser informada. O programa também pode simplesmente esperar por um evento, como o clique do mouse. Se o programa não produzir os resultados desejados, é necessário voltar e reanalisar a lógica. Isso é conhecido como fase de depuração, durante a qual é feita uma tentativa de correção de todos os problemas ou bugs descobertos do programa. Os programas são desenvolvidos em uma sequência de edição, compilação, linkedição e execução. Depois que o código-fonte foi digitado em um editor de texto, o compilador verifica sua sintaxe e, se ela estiver correta, cria um arquivo intermediário chamado de arquivo-objeto (.obj). A partir desse, o linkeditor criará o 76 Unidade II arquivo-executável (.exe), a partir da ligação do arquivo-objeto com as funções providas pelas bibliotecas correspondentes. Os erros que podem surgir em programação são do tipo lógico (bug) ou de sintaxe. No primeiro, o programa não gera o resultado esperado; portanto, é mais perigoso que o segundo, no qual as regras da linguagem são violadas mas o compilador barra a geração do arquivo executável até que o erro seja corrigido (SOFFNER, 2013, p. 36). 4.1.6 Nomenclatura dos identificadores (nome das variáveis) De acordo com Oram e Naik [ca. 2010], os identificadores são palavras definidas pelo usuário para nomear entidades como variáveis, matrizes, funções, estruturas etc. As regras para nomear identificadores são: • o nome deve consistir apenas de alfabetos (maiúsculas e minúsculas), dígitos e sinal de sublinhado (_); • os primeiros caracteres devem ser alfabéticos ou sublinhados; • o nome não deve ser uma palavra-chave; • como a linguagem em C diferencia maiúsculas de minúsculas, as maiúsculas e minúsculas são consideradas de maneira diferente; • os identificadores geralmente são dados em algum nome significativo, como valor, idade, dados etc. 4.2 Estrutura e estilo de programas em linguagem C 4.2.1 Palavra-chave (keyword) Há certas palavras reservadas para realizar tarefas específicas nos programas em C. Essas palavras são conhecidas como palavras reservadas ou palavras-chave. Essas palavras são predefinidas e sempre devem ser escritas em letras minúsculas. Vale ressaltar que tais palavras-chave não podem ser usadas como nome de uma variável com significado fixo. De acordo Soffner (2013), a linguagem C possui um total de 32 palavras reservadas (conforme definido pela American National Standards Institute – ANSI), listadas no quadro a seguir. 77 ALGORITMOS Quadro 5 – Palavras reservadas da Linguagem C Auto Double Int Struct Break Else Long Switch Case Enum Register Typedef Char Extern Return Union Const Float Short Unsigned Continue For Signed Void Default Goto Sizeof Volatile Do If Static While Fonte: Soffner (2013, p. 36). 4.2.2 Sequências de escape Sobre a sequência de escape, Soffner sintetiza bem o assunto ao dizer: Utilizamos também uma sequência (ou um caractere) de escape “\n”, que executa uma operação de formatação no texto impresso na tela. As principais sequências de escape são: \n = newline (nova linha) \a = ASCII beep b = backspace \f = form feed (avanço de página) r = carriage return (enter) \t = tabulação horizontal \\ = barra invertida \’ = aspas simples \” = aspas duplas \? = interrogação \xnn = caractere ASCII em hexadecimal (nn); Exemplo: \xDC, \xC9, \xCD (SOFFNER, 2013, p. 38). 4.2.3 Especificadores de formato Retomemos as palavras de Soffner sobre o assunto: Os especificadores de formato, que, como o nome diz, formatam a entrada e a saída-padrão. São eles: %d = inteiro decimal %f = real (ponto flutuante) 78 Unidade II %o = inteiro octal %x = hexadecimal %c = caractere em formato ASCII %s = string de caracteres %p = valor ponteiro (SOFFNER, 2013, p. 38). 4.3 Tipos e variáveis primitivos 4.3.1 Tipos de dados (data types) Oram e Naik [ca. 2010] apontam que os tipos de dados se referem a um amplo sistema usado para declarar variáveis ou funções de tipos diferentes antes de seu uso. O tipo de uma variável determina quanto espaço ela irá ocupar no armazenamento e como o padrão de bits armazenado é interpretado. Vale ressaltar que o valor de uma variável pode ser alterado a qualquer momento. A linguagem C possui os seguintes tipos de dados: • Internos básicos (basic built-in data types): int, float, double, char. • De enumeração (enumeration data type): enum. • Derivados (derived data type): pointer, array, structure, union. • Nulos (void data type): void. Uma variável do tipo int pode ser usada somente para conter valores integrais (ou seja, valores que não contêm casas decimais). Uma variável do tipo float pode ser usada para armazenar números de ponto flutuante (valores contendo casas decimais). O tipo double é igual ao tipo float, apenas com aproximadamente duas vezes sua precisão. Uma variável char pode armazenar apenas o valor do tipo de caractere (o tipo de dados char pode ser usado para armazenar um único caractere, como a letra a, o caractere de dígito 6 ou um ponto e vírgula da mesma forma). 4.3.2 Variáveis (variables) Variável é um nome de dados usado para armazenar algum valor de dados ou nomes simbólicos para armazenar os cálculos e resultados que serão executados pelo programa. O valor da variável pode ser alterado durante a sua execução. A regra para nomear as variáveis é igual à regra para nomeação do identificador. É sempre recomendável que se inicialize uma variável com um valor adequado para evitarmos erros de tempo de execução, pois essa variável pode reter valores anteriores que gerarão surpresas desagradáveis durante a execução do programa. 79 ALGORITMOS O nome da variável deve sempre lembrar o que vai guardar, e não pode ser igual às palavras reservadas da linguagem. A vírgula em Linguagem C é o ponto, e vice-versa (ao contrário do que fazemos no Brasil). Quando não se declara o tipo da variável, o compilador assume o tipo int. Exemplos de declarações adequadas de variáveis: int habitantes = 200000; // cidadãos de uma cidade short int pessoas = 20; // grupo pequeno de pessoas char letra = ‘a’; // caractere ‘a’ float salario = 1000.00; // valor monetário, com duas casas decimais (SOFFNER, 2013, p. 34, grifo do autor). Antes de ser usado no programa, o valor deve ser declarado. A declaração de variáveis especifica seu nome e tipos de dados (o intervalo do valor que as variáveis podem armazenar depende de sua classificação). Sintaxe: int a; char c; float f; 4.3.2.1 Inicialização das variáveis (variable initialization) Quando atribuímos qualquer valor inicial à variável durante a declaração, esse processo é chamado de inicialização de variáveis. Devemos atribuir o tipo de dado, incluir o nome da variável e a sua constante. Data type Nome_variavel = constante; Exemplo: int valorA = 20; ou int valorA; valorA =20; 80 Unidade II Saiba mais A obra indicada a seguir pode ajudá-lo a entender mais detalhes sobre vários conceitos estudados aqui. SOFFNER, R. Algoritmos e programação em linguagem C. São Paulo: Saraiva, 2013. 4.4 Operadores matemáticos e lógicos 4.4.1 Expressões Uma expressão é uma combinação de variáveis, constantes, operadores e chamadas da função. Pode ser aritmética, lógica e relacional. Veja alguns exemplos. // expressão aritmética int z = x + y; // relacional a > b // lógico a == b // chamada de função func (a, b) Expressões que consistem inteiramente em valores constantes são chamadas de expressões constantes. Veja um exemplo a seguir. 121 + 17 – 110 Essa expressão é denominada constante porque cada um de seus termos é composto de um valor constante. Caso fosse declarada uma variável inteira, a expressão não representaria uma expressão constante. Veja o caso a seguir.180 + 2 - j 4.4.2 Operadores Os operadores são os símbolos usados para executar alguma operação em variáveis, operandos ou constante. Existem vários operadores que podem ser utilizados nas linguagens de programação: operador aritmético, atribuição, incremento, decremento, lógico, condicional, vírgula, entre outros. 81 ALGORITMOS Operador aritmético Esse operador é utilizado para a realização de cálculos numéricos. Podemos classificar os operadores aritméticos como operadores unários e operadores binários. O operador aritmético unário é necessário apenas um operando como as atribuições +, -, ++, --. E os operadores podem utilizar os princípios matemáticos como: + (adição), - (subtração), * (multiplicação), / (divisão). O operador aritmético binário, por outro lado, utiliza obrigatoriamente dois operandos requeridos e seus operadores são: + (adição), - (subtração), * (multiplicação), / (divisão), % (módulo). No módulo, não pode ser aplicado com um operando de ponto flutuante (número real), bem como não há operador expoente em C. Podemos usar ainda: +=, -=, *=, /= Operador de atribuição Um valor pode ser armazenado em uma variável com o uso do operador de atribuição. O operador de atribuição (=) é usado na declaração de atribuição e na expressão de atribuição. O operando no lado esquerdo deve ser a variável e o operando no lado direito pode ser uma variável, uma constante ou qualquer expressão. Por exemplo: int x = y int somaValorProduto = produto1 + produto 2 + produto 3 Incremento e decremento Os operadores unários ++ e -- são usados como incremento e decremento que atuam sobre um único operando. O operador de incremento (++) aumenta o valor da variável em um, já o operador de decremento (--), semelhantemente, diminui o valor da variável em um. Esses operadores podem ser usados apenas com a variável; não podendo ser usados com uma expressão ou uma constante, como nos exemplos a seguir. ++ 6 ++ (x + y + z) 82 Unidade II Operador relacional É usado para comparar o valor de duas expressões, dependendo de sua relação. A expressão que contém operador relacional é denominada expressão relacional. Nessa estrutura, o valor é atribuído de acordo com o parâmetro true (verdadeiro) ou false (falso). Quadro 6 – Operador relacional = = Igualdade < Menor > Maior >= Maior ou igual <= Menor ou igual != Diferente Por exemplo: (a >= b) || (b> 50) (b> a) && (c> b) (a != 80) Operador lógico ou booleano O operador lógico deve ser usado com um ou mais operandos e retorna o valor zero (caso a afirmação seja falsa) ou um (caso a afirmação seja verdadeira). O operando pode ser uma constante, variáveis ou expressões. A expressão que combina duas ou mais expressões é denominada expressão lógica. Quadro 7 – Os três operadores lógicos de C && e || ou ! não O operador ! (não) é unário e os outros dois operadores são binários. O operador lógico && (e) fornece o resultado true se as duas condições forem verdadeiras, caso contrário, o resultado é false. Já o operador lógico || (ou) fornece resultado true se uma das validações forem atendidas, caso contrário, o resultado será false. 83 ALGORITMOS 4.5 Estrutura de decisão e laços de repetição Geralmente, a instrução do programa na linguagem em C é executada na ordem em que aparece no programa, mas, às vezes, usamos condições de tomada de decisão para executar apenas uma parte do programa, a chamada instrução de controle. A instrução de controle define como o controle é transferido de uma parte para a outra parte do programa. É possível utilizar várias instruções de controle como as estruturas if...else, case, while, do...while e for. Neste tópico, vamos trabalhar esses princípios. 4.5.1 Estrutura de decisão Segundo Soffner: Você já reparou que tomamos decisões o tempo todo? Quando caminhamos dentro de casa, quando precisamos aplicar nosso dinheiro, quando aparece um problema em casa ou no trabalho, no trânsito – as decisões são parte da natureza de sobrevivência do animal neste planeta e, em especial, da nossa, dos seres humanos, em razão da racionalidade característica da espécie –; assim, decisões são tomadas a todo o momento, conscientemente ou não (SOFFNER, 2013, p. 46). If A instrução if executa um conjunto de comandos apenas quando a condição é verdadeira. Se o corpo da instrução if consistir em várias afirmações, é necessário utilizar um par de chaves para organizar a sua validação. Caso a condição seja falsa, o compilador irá executar o próximo bloco de instruções. Sintaxe: if (condição / teste) { //Declaração 1; //Declaração 2; } Veja um exemplo a seguir. 84 Unidade II A) B) Figura 31 – Exemplo da estrutura condicional: if (imagem do programa Dev C++) Retomemos o que diz Manzano: Como um exemplo, considere o seguinte problema: ler dois valores numéricos, efetuar a adição e apresentar o seu resultado caso o valor somado seja maior que 10. Veja o diagrama de blocos e a codificação em português estruturado. Algoritmo 1. Conhecer dois valores incógnitos (estabelecer variáveis A e B). 2. Efetuar a soma dos valores incógnitos A e B, implicando o valor da soma na variável X. 3. Apresentar o valor da soma na variável X, caso seja maior que 10 (MANZANO, 2012, p. 60). 85 ALGORITMOS Início Fim A, B Diagramação Codificação X ← A + B X X > 10 N S Figura 32 – Exemplo da utilização da estrutura se...então (if) A partir dessa representação, é possível implementar o programa na linguagem de programação C. A seguir é dado o código. 86 Unidade II A) B) Figura 33 – Implementação do problema apresentado (imagem do programa Dev C++) If...else A estrutura if...else é uma declaração de controle condicional bidirecional que contém uma condição e duas ações possíveis. A condição pode ser verdadeira ou falsa, sendo o valor diferente de zero considerado verdadeiro e zero considerado falso. Se a condição for verdadeira, então um único ou um bloco de declaração será executado, caso contrário, outro único ou bloco de declaração será executado. Sintaxe: if (condição / teste) { //Declaração 1 //Declaração 2 } else { //Declaração 1 //Declaração 2 } 87 ALGORITMOS Veja o exemplo a seguir. A) B) Figura 34 – Exemplo da estrutura condicional: if...else (imagem do programa Dev C++) Diz Soffner: Vejamos agora um exemplo de algoritmo que decide se um aluno foi aprovado em dada disciplina escolar, em função das notas recebidas nas avaliações. Teste da aprovação de um aluno Dados de entrada: notas bimestrais. Processamento: cálculo da média final e teste em relação à média de aprovação. Dados de saída: “aprovado” ou “reprovado”. 88 Unidade II O algoritmo receberá duas notas de avaliações, calculará a média aritmética dessas notas e comparará a média com o valor 6,0 (que é a média de aprovação da escola). Agora vem a decisão: se a média for maior ou igual a 6,0 (seis), o aluno está “aprovado”; caso contrário, ele está “reprovado” (SOFFNER, 2013, p. 47, grifo do autor). Média = (N1+N2)/2 Início Fim “Aprovado“ “Reprovado“ N1, N2 Média>=6,0? Sim Não Figura 35 – Representação gráfica da memória de um computador com variáveis A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja a seguir o código. 89 ALGORITMOS A) B) Figura 36 – Implementação do problema apresentado (imagem do programa Dev C++) Else if Nesse tipo de aninhamento, há uma instrução if else em todas as partes, exceto na última. Se a condição for um controle falso, passará para o bloco em que a condição é novamente verificada. Esse processo continua até que não haja instrução if no último bloco, ou seja, caso uma das condições seja atendida (válida), as próximas condições do bloco aninhado “else if” não serão executadas. 90 Unidade II Essa dinâmica possui uma desvantagem sobre a declaração if else: na declaração if else, sempre que a condição for verdadeira, outra condição não será verificada;já aqui, todas as condições serão verificadas de forma hierárquica. Sintaxe: if (condição / teste) { //Declaração 1 //Declaração 2 } else if (condição / teste) { //Declaração 1 //Declaração 2 } else if (condição / teste) { //Declaração 1 //Declaração 2 } else { //Declaração 1 //Declaração 2 } Veja um exemplo a seguir. 91 ALGORITMOS A) B) Figura 37 – Exemplo da estrutura condicional: else if (imagem do programa Dev C++) Segundo Manzano: Desenvolver um programa que solicite a entrada de um valor numérico inteiro e apresente uma das seguintes mensagens: “você entrou o valor 1” se for dada a entrada do valor numérico 1; “você entrou o valor 2” se for dada a entrada do valor numérico 2; “você entrou valor muito baixo” se for dada a entrada de um valor numérico menor que 1 ou “você entrou valor muito alto” se for dada a entrada de um valor numérico maior que 2. Veja a descrição das etapas de entendimento do problema e a representação das ações a serem efetuadas pelo programa: a. Definir a entrada de um valor numérico inteiro (variável N). 92 Unidade II b. Verificar se N = 1 e, se for, apresentar a mensagem “você entrou o valor 1”. c. Verificar se N = 2 e, se for, apresentar a mensagem “você entrou o valor 2”. d. Verificar se N < 1 e, se for, apresentar a mensagem “você entrou valor muito baixo”. e. Verificar se N > 2 e, se for, apresentar a mensagem “você entrou valor muito alto” (MANZANO, 2012, p. 66). Início Fim N Diagrama de blocos Português estruturado “Você entrou o valor 1“ “Você entrou o valor 2“ “Você entrou o valor muito baixo“ “Você entrou o valor muito alto“ N = 1 N = 2 N < 1 N > 2 N N N N S S S S Figura 38 – Exemplo da utilização da estrutura se...então (if) A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. 93 ALGORITMOS A) B) Figura 39 – Implementação do problema apresentado (imagem do programa Dev C++) Switch...Case A instrução Switch...Case testa o valor de uma variável e a compara com vários casos. Depois que a correspondência de caso é encontrada, um bloco de instruções associado a esse caso específico deverá será ser executado. O valor fornecido pelo usuário é comparado com todos os casos dentro do bloco da estrutura Switch...Case até que a correspondência seja encontrada. Se uma correspondência de caso não for encontrada, a instrução padrão será executada e o controle sairá do bloco. 94 Unidade II Sintaxe: switch( expressão ) { case valor-1: //Declaração 1 //Declaração 2 Break; case valor -2: //Declaração 1 //Declaração 2 break; case valor-n: //Declaração 1 //Declaração 2 break; default: //Declaração 1 //Declaração 2 break; } Veja um exemplo a seguir. 95 ALGORITMOS A) B) Figura 40 – Exemplo da estrutura condicional: case (imagem do programa Dev C++) 96 Unidade II Observe a seguir a descrição das etapas básicas de entendimento do problema e a representação das ações a serem efetuadas pelo programa. Algoritmo Efetuar a leitura de um valor numérico inteiro (variável MÊS). Se a variável MÊS for igual a 1, apresentar a mensagem “Janeiro”. Se a variável MÊS for igual a 2, apresentar a mensagem “Fevereiro”. Se a variável MÊS for igual a 3, apresentar a mensagem “Março”. Se a variável MÊS for igual a 4, apresentar a mensagem “Abril”. Se a variável MÊS for igual a 5, apresentar a mensagem “Maio”. Se a variável MÊS for igual a 6, apresentar a mensagem “Junho”. Se a variável MÊS for igual a 7, apresentar a mensagem “Julho”. Se a variável MÊS for igual a 8, apresentar a mensagem “Agosto”. Se a variável MÊS for igual a 9,apresentar a mensagem “Setembro”. Se a variável MÊS for igual a 10, apresentar a mensagem “Outubro”. Se a variável MÊS for igual a 11, apresentar a mensagem “Novembro”. Se a variável MÊS for igual a 12, apresentar a mensagem “Dezembro”. Se a variável MÊS for menor que 1 ou maior que 12, apresentar a mensagem “Valor inválido” (MANZANO, 2012, p. 72). 97 ALGORITMOS Mês=1 Mês=3 Mês=5 Mês=7 Mês=9 Mês=11 Mês=2 Mês=4 Mês=6 Mês=8 Mês=10 Mês=12 “Janeiro“ “Março“ “Maio“ “Julho“ “Setembro“ “Novembro“ “Fevereiro“ “Abril“ “Junho“ “Agosto“ “Outubro“ “Dezembro“ “Valor inválido” Início Fim Mês S S S S S S S S S S S S N N N N N N N N N N N N Diagrama de blocos Português estruturado Figura 41 – Exemplo da tomada de decisão por seleção (case) 98 Unidade II A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja a seguir o código. A) B) Figura 42 – Implementação do problema apresentado (imagem do programa Dev C++) 99 ALGORITMOS 4.5.2 Laços de repetição Os laços de repetição são um bloco de instruções que executam um conjunto de instruções. Nos loops, é possível repetir uma parte específica do programa por um número especificado de tempo ou até que um determinado número de condições seja satisfeito. Existem três tipos de loops em C: • while; • do ... while; • for. While Na estrutura while, a condição de teste pode ser qualquer expressão. Quando queremos repetir uma instrução, mas não se sabe a quantidade exata de iterações, podemos utilizar essa estrutura para realizar as devidas validações. Aqui, a primeira condição é verificada e, caso a validação seja verdadeira, o corpo do loop é executado; caso contrário, se a condição for falsa, o controle sairá do loop. Sintaxe: while (condição / teste) { //Declaração 1; //Declaração 2; } 100 Unidade II Exemplo de aplicação: A) B) Figura 43 – Exemplo da estrutura de repetição: while (imagem do programa Dev C++) A título de ilustração de uso do laço com controle condicional pré-teste verdadeiro em um contexto operacional, considere os problemas a seguir, observando detalhadamente as etapas de ação de um programador de computador: entendimento, diagramação e codificação. Os programas demonstram os laços nas formas iterativa e interativa. 101 ALGORITMOS Exemplo com laço iterativo Elaborar um programa que efetue a entrada de um valor numérico inteiro qualquer. Em seguida, processar o cálculo do valor de entrada, multiplicando-o por 3 e apresentando seu resultado. Proceder à execução dos passos anteriores cinco vezes (MANZANO, 2019). R ← N ⊗ 3 I ← I + 1 I ← 1 I <= 5 R Início Fim N N S Figura 44 – Exemplo da instrução enquanto...faça/fim_enquanto iterativa A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. 102 Unidade II A) B) Figura 45 – Implementação do problema apresentado (imagem do programa Dev C++) Com relação a tal tema, comenta Manzano: No problema exposto, é necessário definir um laço que vai executar a vontade do usuário. Assim, não há possibilidade de saber quantas vezes o laço será executado. O número de vezes vai depender da vontade do usuário, por isso esse tipo de laço chama-se interativo. Atente para os passos descritos a seguir: 103 ALGORITMOS 1. Criar uma variável de controle para ser utilizada como resposta (variável RESP). 2. Enquanto o valor da variável RESP for igual a “S”, executar os passos 3 a 5; caso contrário, desviar a execução do programa para o passo 8. 3. Ler um valor inteiro qualquer (variável N). 4. Efetuar a multiplicação do valor de N por 3, colocando o resultado na variável R. 5. Apresentar o valor calculado que está armazenado na variável R. 6. Perguntar para o usuário se ele deseja continuar a execução do programa. 7. Retornar a execução do programa ao passo 2. 8. Encerrar o programa (MANZANO, 2019, p. 117). R ← N ⊗ 3 RESP←”S” RESP=”S” R “Deseja continuar?“ Início Fim N RESP N S Figura 46 – Exemplo da instrução enquanto...faça/fim_enquanto iterativa 104 Unidade II A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. A) B) Figura 47– Implementação do problema apresentado (magem do programa Dev C++) Do ... while A declaração (do ... while) também é usada para o desenvolvido da estrutura de repetição. O corpo desse loop pode conter uma única declaração ou um bloco de declaração. Sintaxe: do{ //Declaração 1; //Declaração 2; } while (condição); 105 ALGORITMOS A seguir um exemplo da aplicação. A) B) Figura 48 – Exemplo da estrutura de repetição: Do...while (imagem do programa Dev C++) Manzano esclarece: O problema é o mesmo exposto anteriormente. A diferença é a forma de construção da condição e do laço. Atente para os passos descritos a seguir: 1. Criar uma variável de controle para servir como contador com valor inicial 1 (variável I). 2. Ler um valor inteiro qualquer (variável N). 3. Efetuar a multiplicação do valor de N por 3, colocando o resultado na variável R. 106 Unidade II 4. Apresentar o valor calculado que está armazenado na variável R. 5. Acrescentar o valor 1 ao valor existente da variável I, definida no passo 1. 6. Verificar se a variável contador é maior que 5; sendo, executar os passos 2 a 4; caso contrário, desviar o programa para o passo 7. 7. Encerrar a execução do programa. (MANZANO, 2019, p. 123). R ← N ⊗ 3 I ← 1 I ← I + 1 I > 5 R Início Fim N N S Figura 49 – Exemplo de laço repita/até_que iterativa A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. 107 ALGORITMOS A) B) Figura 50 – Implementação do problema apresentado (imagem do programa Dev C++) Segundo Manzano: Por ser um problema semelhante a uma situação já exposta, basta escolher um laço que vai satisfazer a vontade do usuário do programa. Assim, não é possível saber quantas vezes o laço será executado. Atente para os passos descritos a seguir: 1. Criar uma variável de controle para ser utilizada como resposta (variável RESP). 108 Unidade II 2. Ler um valor inteiro qualquer (variável N). 3. Efetuar a multiplicação do valor de N por 3, colocando o resultado na variável R. 4. Apresentar o valor calculado que está armazenado na variável R. 5. Perguntar para o usuário se ele deseja continuar o programa. 6. Caso o valor da variável RESP seja diferente de “S”, executar os passos 2 a 4; caso contrário, ir para o passo 7. 7. Encerrar o programa (MANZANO, 2019, p. 124). R ← N ⊗ 3 RESP ← “S“ RESP <> “S“ R “Deseja continuar?“ Início Fim N RESP N S Figura 51 – Exemplo de laço repita/até_que iterativa A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. 109 ALGORITMOS A) B) Figura 52 – Implementação do problema apresentado (imagem do programa Dev C++) For Em um programa que utiliza a estrutura de repetição for, geralmente conseguimos definir o número de iterações que serão executadas no início do programa. O corpo do loop pode ser composto de uma única instrução ou várias instruções. Sintaxe: for (inicialização; validação; incremento/decremento){ //Declaração 1; //Declaração 2; } 110 Unidade II Observe a seguir um exemplo. A) B) Figura 53 – Exemplo da estrutura de repetição: For (imagem do programa Dev C++) Vejamos o que propõe Manzano: A título de ilustração de uso do laço incondicional em um contexto operacional, considere o problema a seguir, observando detalhadamente as etapas de ação de um programador de computador: entendimento, diagramação e codificação. Elaborar um programa que efetue a entrada de um valor numérico inteiro qualquer. Em, seguida, calcular o valor de entrada, multiplicando-o por 3 e apresentando seu resultado. Proceder à execução dos passos anteriores cinco vezes (MANZANO, 2019, p. 132). 111 ALGORITMOS R ← N ⊗ 3 R Início Fim N I ← 1, 5, 1 Figura 54 – Exemplo do laço execute/ enquanto_for iterativo Continuemos seguindo o raciocínio de Manzano: O problema exposto já é conhecido, mas desta vez sua operação será mais dinâmica. Atente para os passos descritos a seguir: 1. Definir uma variável do tipo contador (variável I), variando de 1 a 5, de 1 em 1. 2. Ler um valor inteiro qualquer (variável N). 3. Efetuar a multiplicação do valor de N por 3, colocando o resultado na variável R. 4. Apresentar o valor calculado que está armazenado na variável R. 5. Repetir os passos 2, 3, 4 e 5 até o valor da variável chegar a 5. 6. Encerrar a execução do programa. O conjunto de instruções subordinadas ao bloco adjacente é executado entre os comandos para e fim_para, sendo a variável I (variável de controle) inicializada com valor 1 e incrementada de mais 1 por meio do comando passo até a variável I atingir o valor 5. Esse tipo de estrutura pode ser utilizado todas as vezes que houver a necessidade de repetir trechos finitos, em que se conhecem os valores do laço: inicial, final e incremento (MANZANO, 2019, p. 133). 112 Unidade II A partir dessa representação, é possível implementar o programa na linguagem de programação C. Veja o código a seguir. A) B) Figura 55 – Implementação do problema apresentado (imagem do programa Dev C++) Resumo Vimos que a estrutura de dados é uma forma de organizar dados na memória de um computador, uma maneira específica de armazenar e organizar dados em um computador para que possam ser usados com eficiência. Diferentes tipos de estruturas de dados são adequados para diferentes tipos de aplicativos e, em alguns casos, são altamente especializados para realizar tarefas específicas. As estruturas de dados são usadas em quase todos os programas ou sistemas de software. Estruturas de dados específicas são ingredientes essenciais de muitos algoritmos eficientes e possibilitam o gerenciamento 113 ALGORITMOS de enormes quantidades de dados, como grandes bancos de dados e serviços de indexação de internet. Observou-se que a utilização de matrizes em programação é bastante ampla, indo desde o uso direto, quando o programador constrói a estrutura de dados e faz o seu controle operacional, até o uso indireto, quando o programador usa um sistema de gerenciamento de banco de dados para auxiliar a construção e o controle das operações em tabelas de dados. Geralmente, a instrução do programa na linguagem em C é executada na ordem em que aparece no programa, mas, às vezes, pode-se usar condições de tomada de decisão para executar apenas uma parte do programa, a instrução de controle. A instrução de controle define como o controle é transferido de uma parte para a outra parte do programa. Vimos ainda que a instrução if executa um conjunto de comandos apenas quando a condição dada é verdadeira. Se o corpo da instrução if consistir em várias afirmações, é necessário utilizar um par de chaves para organizar a sua validação. Caso a condição seja falsa, o compilador irá executar o próximo bloco de instruções. Já a estrutura if...else é uma declaração de controle condicional bidirecional que contém uma condição e duas ações possíveis. A condição pode ser verdadeira ou falsa, sendo o valor diferente de zero considerado verdadeiro e zero considerado falso. Se a condição for verdadeira, então um único ou um bloco de declaração será executado, caso contrário, outro único ou bloco de declaração será executado. A instrução switch...case testa o valor de uma variável e a compara com vários casos. Depois que a correspondência de caso é encontrada, um bloco de instruções associado a esse caso específico deverá será ser executado. O valor fornecido pelo usuário é comparado com todos os casos dentro do bloco da estrutura Switch...Case até que a correspondência seja encontrada. Se uma correspondência de caso não for encontrada, a instrução padrão será executada e o controle sairá do bloco. Encerramos a unidade abordando sobre os laços de repetição que são um bloco de instruções que executam um conjunto de instruções. Nos loops é possível repetir uma parte específica do programa por um número especificado de tempoou até que um determinado número de condições seja satisfeito. Existem três tipos de loops de repetição: While, Do ... While e For. 114 Unidade II Exercícios Questão 1. Considere o código em C a seguir e analise as afirmativas. #include <stdio.h> void main() { int break; break = 3 + 2; printf(“%i”, break); } I – O código faz a soma de números inteiros dados pelo usuário do programa. II – O código apresenta erro por utilizar uma palavra reservada como variável. III – O código apresenta erro na linha em que se faz a saída de dados. IV – A primeira linha do código usa uma biblioteca com as funções padrão de entrada e de saída de dados. É correto o que se afirma apenas em: A) I e III. B) II e IV. C) I e IV. D) I, III e IV. E) IV. Resposta correta: alternativa B. Análise das afirmativas I – Afirmativa incorreta. Justificativa: note que não temos entrada de dados por parte do usuário, o que poderia ocorrer pela função scanf() se os dados fossem digitados na tela. O programa faz o cálculo a partir dos números dados no próprio código e retorna, portanto, sempre o mesmo resultado. 115 ALGORITMOS II – Afirmativa correta. Justificativa: no código, é usada a variável break, uma palavra reservada da linguagem C que não pode ser usada para nomear uma variável. O comando break interrompe um bloco de código. III – Afirmativa incorreta. Justificativa: a linha que faz a saída de dados é a seguinte: printf(“%i”, break); Como primeiro argumento da função, temos o tipo de variável que desejamos usar para impressão, e %i indica tipo inteiro, que é como a variável foi definida. Como segundo argumento, temos o nome da variável que deve ser impressa. A sintaxe dessa linha de código está correta. IV – Afirmativa correta. Justificativa: a primeira linha do código faz a inclusão da biblioteca stdio.h, que contém as funções básicas (std) de entrada e saída (io) de dados. Sem incluirmos essa biblioteca, não poderíamos usar a função printf no código. Questão 2. Considere o programa em C a seguir e analise as afirmativas. #include <stdio.h> #include <stdlib.h> int main (void) { int a, b, c; b=0; printf(“Digite dois números inteiros \n”); scanf(“%i”,&a); scanf(“%i”,&c); while (a*b <2) { a=a+2; b=b+2; c=c+2; } printf(“%i”,a*b*c); } 116 Unidade II I – O programa usa três variáveis do tipo inteiro, duas com valor fornecido pelo usuário e uma com valor atribuído no código. II – O programa não apresenta uma estrutura de repetição. III – A condição da função while() é a seguinte: o produto do valor contido na variável a quando multiplicado pelo valor contido na variável b é menor do que 2. IV – Quando executado o programa, os valores contidos em todas as variáveis são somados de duas unidades pelo menos uma vez, independentemente dos valores fornecidos pelo usuário. É correto o que se afirma apenas em: A) I e II. B) I, II e III. C) I e III. D) II, III e IV. E) III e IV. Resposta correta: alternativa A. Análise das afirmativas I - Afirmativa correta. Justificativa: na declaração de variáveis, vemos que o programa tem três variáveis do tipo inteiro. int a, b, c; Em seguida, vemos que b tem valor inicial fixo determinado pelo código: b=0; Confirmamos que o conteúdo das variáveis a e c são dados pelo usuário do programa por meio da função de entrada de dados scanf(): scanf(“%i”,&a); scanf(“%i”,&c); 117 ALGORITMOS II – Afirmativa correta. Justificativa: no código, é usada a variável break, e essa é uma palavra reservada da linguagem C, não podendo ser usada para nomear uma variável. O comando break interrompe um bloco de código. III – Afirmativa incorreta. Justificativa: o argumento passado para a função while() é a condição para a permanência no looping. No caso, temos: while (a*b <2) Logo, vemos que a condição de permanência é a seguinte: o produto dos valores contidos nas variáveis a e b é menor do que 2. IV – Afirmativa incorreta. Justificativa: a condição de entrada/permanência na estrutura de repetição é a*b<2. O código atribui valor zero para b. O valor de a é dado pelo usuário. Logo, independentemente do valor de a, temos a*b=0, e a condição é satisfeita. Concluímos que a estrutura de repetição é executada pelo menos uma vez.
Compartilhar