Baixe o app para aproveitar ainda mais
Prévia do material em texto
ALGORITMOS E ESTRUTURAS DE DADOS I Monitores: Bianca Lopes Magri - biancalopes@gec.inatel.br Carlos Henrique Jacinto - carlosjacinto@gec.inatel.br Eliza Aparecida Crisóstomo Reis - elizaaparecida@get.inatel.br Heitor Toledo Lassarote de Paula - heitortoledo@gec.inatel.br Maycon Geraldo Alves - mayconalves@gea.inatel.br Créditos: Dâmi Henrique Pelegrino Instituto Nacional de Telecomunicações - Inatel 2017 1 Sumário 1. Introdução 5 1.1. Linguagem de programação 5 1.2. IDE 5 2. Código 8 2.1. Bibliotecas 9 2.2. Using namespace 9 2.3. Função principal 9 2.4. Comentários 10 2.4.1. Comentário de uma linha 10 2.4.2. Comentário de mais de uma linha (bloco) 10 2.5. Ponto e vírgula (;) 10 3. Variáveis 12 3.1. Tipos de variáveis 13 3.1.1. Variáveis numéricas 13 3.1.1.1. int 13 3.1.1.2. long long int 14 3.1.1.3. float 14 3.1.1.4. double 14 3.1.2. Variáveis alfanuméricos 14 3.1.2.1 char 14 3.1.3. Variáveis lógicas 14 3.1.3.1. bool 15 3.2. Declaração de variáveis 15 3.3. Operadores 15 3.4. Atribuindo valores 15 3.4.1. Divisão de inteiros 16 4. Entrada e saída de dados 17 4.1. Entrada de dados 17 4.1.1. Entrada de textos 18 4.1.1.1. Comando cin.ignore() 18 4.2. Saída de dados 19 4.2.1. Comando endl 20 4.2.2. Comando setprecision 21 5. Debug 22 6. Estruturas de Decisão 25 2 6.1. A estrutura if-else 25 6.1.1. O comando if 25 6.1.2. O comando else 28 6.1.3. If-else aninhado 29 6.1.4. If-else encadeado 30 6.2. Switch 32 7. Abreviações 36 8. Estruturas de repetição 38 8.1. While 39 8.2. Do-While 44 8.3. For 48 8.4 Loop Infinito 51 8. Vetores 53 8.1. Declaração 53 8.2. Atribuindo valores 54 9. Manipulação de Strings 55 9.1. Caracter ‘\0’ 56 9.2. Atribuição de valores à variáveis char 56 9.2.1. Criando manualmente 56 9.2.2. Atribuindo na criação 56 9.3. Funções prontas para manipular Strings 57 9.3.1. Tamanho da string 57 9.3.2. Comparação entre Strings 57 9.3.3. Copiando uma String 58 9.3.4. Verificação de letra e número 58 9.3.4.1. Verificação de letra 58 9.3.4.2. Verificação de número 59 9.4. Percorrendo uma String 59 10. Matriz 60 10.1. Declaração 60 10.2. Atribuindo valores 61 11. Funções 62 11.1. Vantagens 63 11.2. Funcionamento 63 11.3. Estrutura de uma Função 63 11.3.1. Nome da Função 63 11.3.2. Parâmetros 64 11.4.3 Variáveis Globais e Locais 64 11.4.4 - Tipo da Função 64 3 11.5.4 - Funções com passagem de parâmetros por referência 66 11.5.4.1 - Ponteiros 66 11.5.4.2 - Endereço de memória 67 11.5.3 - Passando parâmetros por referência 67 11.5.5 - Funções com retorno 67 11.5.6 - Funções sem retorno 68 11.6 - Prototipagem 68 12. Struct 69 12.1. Definição e declaração de uma struct 69 12.2. Acesso aos membros de uma struct 70 12.3. Vetor de struct 71 12.4. Passagem de struct para função 72 12.5. Função com retorno de struct 75 13. Arquivos 76 13.1. A biblioteca fstream 76 13.2. Abrindo e fechando um arquivo 76 13.3. Cursores de leitura e escrita 77 13.4. Escrevendo em um arquivo 78 13.5. Lendo de um arquivo 79 13.6. Buscando um dado no arquivo 80 13.7. Editando um dado no arquivo 81 13.8. Excluindo um dado no arquivo 81 13.8.1. Exclusão lógica 82 13.8.2. Exclusão física 82 13.8.2.1. Exclusão física utilizando arquivo auxiliar 82 13.8.2.2. Exclusão física utilizando vetor de registros 83 4 1. Introdução 1.1. Linguagem de programação A linguagem de programação utilizada no laboratório será a linguagem C/C++ estruturada. Para que o computador possa fazer o que nós queremos é preciso programá-lo, ou seja, usar instruções (no nosso caso serão instruções da linguagem C/C++) para que o computador possa entender o que ele tem que fazer. Porém, a única linguagem que o computador entende é a linguagem de máquina, sendo assim, é preciso traduzir a linguagem de programação na linguagem do computador. O processo de tradução é chamado de compilação. Só depois disso é possível executar e ver o programa em funcionamento. 1.2. IDE A IDE (Integrated Development Environment ou Ambiente Integrado de Desenvolvimento) é um programa onde é possível escrever o código, compilá-lo e executá-lo. Na nossa aula será usado como IDE o Falcon C++. Visão inicial da IDE: Para abrir um novo arquivo você pode usar o atalho CTRL+N ou então clicar na seguinte opção: 5 Depois disso já é possível começar a escrever o código: 6 Para compilar um código pode-se usar o atalho CTRL+F9. Para compilar e executar ao mesmo tempo pode-se usar a tecla F9. Também é possível acessar essas operações através dos botões de setas como mostra a figura. 7 2. Código O template inicial dos nossos códigos será: 1. #include<iostream> 2. 3. using namespace std; 4. 5. int main (){ 6. 7. //código 8. 9. return 0; 10. } 2.1. Bibliotecas Bibliotecas são coleções de funções e comandos pré-definidas que auxiliam e facilitam o trabalho do programador. Para usar qualquer função pronta da linguagem é preciso declarar a biblioteca onde está função está contida, ou seja, deve-se incluir essa biblioteca ao código. Para se incluir uma biblioteca deve-se usar o comando #include<>. Por exemplo: para incluir a biblioteca iostream, faz-se: #include<iostream> 2.2. Using namespace O comando using namespace serve para definir uma “espaço de nome”, namespace, que nada mais é que uma estrutura do C++ que serve para definir escopos para as estruturas dessa linguagem como classes, constantes, funções etc. No nosso caso, utilizaremos o namespace std para nos poupar tempo na realização dos nossos códigos uma vez que com o comando using inserido no programa não será necessário definir em cada linha de código qual namespace estaremos utilizando. Veja o exemplo de como seria o código ao lado sem o comando using namespace std: 8 2.3. Função principal A função principal é a primeira coisa a ser executada no programa. Ela é identificada pela função int main(). A princípio todo o código será escrito dentro dessa função principal. O comando return 0 que está dentro da função int main() identifica o final da execução do código. Ou seja, ao chegar nesse comando o compilador finaliza a execução. 2.4. Comentários Comentários são textos que fazem partes do código mas são desprezados na hora da execução, sendo importantes apenas para o entendimento e explicitação do código e seu funcionamento. Nele é aceito qualquer tipo de caractere. 2.4.1. Comentário de uma linha Deve vir depois de duas barras como no exemplo a seguir: // conteúdo após as barras são comentários. Não pode ultrapassar uma linha. 2.4.2. Comentário de mais de uma linha (bloco) Deve ficar depois de /* e antes de */ como no exemplo a seguir: /* aqui fica o bloco de comentário que pode se estender por quantas linhas forem necessárias */ 2.5. Ponto e vírgula (;) No C/C++, ponto e vírgula significa final de comando. Assim, deve-se sempre adicionar um ponto e vírgula no final de todos os comandos. Caso isso não ocorra o compilador provavelmente acusaráum erro, como no exemplo a seguir: 9 Ao executar será exibida a aba de mensagens na parte inferior da IDE. Essa aba nos informa se a compilação ocorreu de forma correta ou se houve algum erro. O código anterior possui um erro de sintaxe na linha 9. Após o comando return 0 faltou um ponto e vírgula para finalizar. O compilador mostrará o seguinte erro: 10 A aba de Mensagens abaixo apresenta a seguinte mensagem: “Era esperado um ‘;’ antes do símbolo ‘}’” A linha referente ao ‘}’ será mostrado com uma linha vermelha no código. Assim sabe-se que no comando anterior a esse falta um ponto e vírgula. Atente-se que o erro de falta de ponto e vírgula sempre acusará erro no comando posterior ao que falta o ‘;’. Ou seja, no exemplo anterior faltou-se o ‘;’ na linha 9, mas a linha vermelha foi mostrada da linha 10, pois não foi possível executar a linha 10 por causa dessa falha. Já em outros tipos de erro a linha vermelha aparece na linha exata do erro. 11 3. Variáveis Variáveis são posições reservadas na memória do computador usadas para armazenamento dos dados que serão manipulados no programa. Os dados salvos em uma variável podem ser modificados a qualquer momento. Estas posições de memória devem ser reservadas previamente para que possam ser usados pelo código. Essa operação é chamada de declaração de variável. Na declaração de uma variável deve-se informar o tipo de dado que será salvo nela e depois o nome que deseja dar a ela (será através deste nome que o espaço da memória será acessado). Tipo_da_variável Nome_da_variável; Os nomes de variáveis devem seguir algumas regras: - Deve começar sempre com uma letra (A-Z ou a-z) ou underscore ( _ ); - O restante deve conter apenas letras, underscore ou números; - Letras maiúsculas são diferentes de minúsculas. Por exemplo: nome, NOME, Nome. Seriam 3 variáveis diferentes; - As variáveis não podem ter o mesmo nome que uma palavra reservada pelo C++. Segue abaixo uma tabela de palavras reservadas pelo C++, e que não podem ser utilizadas como nome de variáveis: Fonte: cppreference.com 12 É interessante que os nomes das variáveis sejam sugestivos, ou seja, façam referência à informação em que a variável irá ter salvo nela. Por exemplo: primeiroNome -> irá guardar o primeiro nome da pessoa. idade -> irá guardar uma idade 3.1. Tipos de variáveis Como mostrado no item anterior, para se declarar uma variável é preciso definir o tipo dela, ou seja, o que ela será capaz de guardar em seu espaço na memória. 3.1.1. Variáveis numéricas São variáveis que guardam dados numéricos para que estes, por exemplo, sejam usados em diversos tipos de cálculos. Segue tabela de cada tipo de variável numérica: Tipo Descrição Limite de armazenamento Exemplos Declaração int Guardam números inteiros -2147483648 até 2147483647 10; 0; -454; 230; int nome_da_variavel; long long int Guardam números inteiros (limite maior) -9223372036854775808 até -9223372036854775808. 10; 0; -454; 230; long long int nome_da_variavel; float Guardam qualquer número real aproximadamente 10-38 até 1038 (precisão de 7 dígitos) 2.1; -820.32; 0; 18.9; float nome_da_variável; double Guardam qualquer número real (limite maior) aproximadamente 10-4932 até 10 4932 (precisão de 15 dígitos) 2.1; -820.32; 0; 18.9; double nome_da_variável; Obs.: As casas decimais são separadas por ponto e não por vírgula. No código, a vírgula separa comandos e declarações de variáveis e o ponto em variáveis numéricas separa a parte inteira da parte decimal do número. 13 3.1.2. Variáveis alfanuméricos São variáveis que podem salvar textos e caracteres. Podem armazenar letras, caracteres especiais, números ou a combinação de tudo isso, mas não poderão ser usados em cálculos numéricos pois tem a funcionalidade meramente de texto. 3.1.2.1 char Pode receber qualquer tipo de caractere. É necessário o tamanho da variável junto com a declaração da variável, ou seja, é preciso especificar a quantidade máxima de caracteres que poderá ser guardado nessa variável. Limite da variável: definida na declaração entre colchetes [ ]. Exemplos: “Bianca”, “3471-1234”, “035”, “Faculdade: Inatel”. Declarando: char nome[30]; Obs.: Caso não seja fornecido o tamanho máximo da variável, seu tamanho será automaticamente 1. Ou seja, só será possível salvar um caractere dentro dessa variável. Declarando: char letra; 3.1.3. Variáveis lógicas São variáveis que guardam apenas dois valores: true (verdadeiro) ou false (falso) que podem ser identificados pelos valores numéricos 0 (falso) ou 1 (verdadeiro). É importante notar que o C/C++ considera qualquer número igual a 0 como falso, e qualquer número diferente de 0 como verdadeiro. 3.1.3.1. bool Variável binária: apenas 0 ou 1. Exemplo: true, false. Declarando: bool nome_da_variavel; 3.2. Declaração de variáveis É possível declarar mais de uma variável no mesmo comando, contanto que elas sejam todas do mesmo tipo. Exemplo: int valor1, valor2, valor3; De outra forma, é possível também declará-las separadamente: Exemplo: int valor1; int valor2; int valor3; 14 3.3. Operadores Para realizar cálculos matemáticos é preciso usar alguns operadores. Segue alguns que serão bastante usados: - Atribuição de valor: = - Soma: + - Subtração: - - Multiplicação: * - Divisão: / - Resto da divisão: % O operador % só pode ser usado com valores inteiros. 3.4. Atribuindo valores Para atribuir valor para variáveis numéricas e lógicas basta usar o operador igual “=”. A atribuição de variáveis alfanuméricas será abordada no tópico de Strings. Caso nenhum valor seja inicialmente atribuído a uma variável, ela terá um valor aparentemente aleatório dentro dela, chamado de lixo. Isto ocorre pois um espaço de memória antes de ser utilizado por uma variável pode ter um valor deixado de sobra, e quando a variável é alocada na memória, ela começa com este valor. Exemplo para variáveis numéricas: 1. double valor; 2. valor = 10.5; ou 1. double valor = 10.5; Exemplo para variáveis lógicas: 1. bool valor; 2. valor = true; ou 1. bool valor = true; Além de atribuir uma constante também é possível atribuir à uma variável o resultado de uma operação, da seguinte forma: 1. int valorA, valorB, valorC, valorD; 2. 3. valorA = 1+2; //a variável recebe 3, que é o resultado da soma 15 4. valorB = 4*valorA; //a variável recebe o resultado de 4 multiplicado pelo valor da variável valorA 5. valorC = 11%3; //a variável vai receber o resto da divisão de 11 por 3. No caso o resto é 2. 6. valorD = valorA/2; //a variável vai receber o valor da divisão de 3 (valor da variável valorA) por 2; 3.4.1. Divisão de inteiros Atenção: a divisão de dois valores inteiros (como mostrado na operação valorD = valorA / 2) irá resultar no valor 1 e não em 1.5.Isso acontece porque ao executar a divisão de dois valores inteiros o compilador dá como resposta um resultado inteiro, independente do real valor dessa divisão. Sendo assim, caso queira que a divisão resulte em seu valor correto, deve-se passar um dos dois valores da divisão para um valor float/double. Algumas possibilidades são: 1. double valorA, valorD; 2. 3. valorA = 1+2; 4. valorD = valorA/2; // agora a variável valorA é double e a divisão é feita corretamente ou 1. int valorA; 2. double valorD; 3. 4. valorA = 1+2; 5. valorD = valorA/2.0; // agora a constante 2.0 tem casas demais, 6. //portanto é lido como um valor double, e a divisão é feita corretamente 16 4. Entrada e saída de dados Comandos de entrada e saída de dados são os que nos permitem interagir com o usuário através de dispositivos de saída (por exemplo, o monitor) e de entrada (por exemplo, o teclado). A interface que possibilitará a interação do usuário com o executável do código será o terminal de comandos do computador. Para usar os comandos de entrada e saída de dados é preciso antes declarar a biblioteca iostream. 4.1. Entrada de dados São dados fornecidos pelo usuário que são salvos nas variáveis declaradas no código. O comando que possibilita a entrada de dados é o cin (nome sugestivo para a entrada pois o nome é composto pela letra ‘c’ que refere-se ao ‘c’ da linguagem + ‘in’ que significa dentro). O comando cin é acompanhado por dois sinais de maior ‘>>’. O comando cin grava o dado digitado pelo usuário na variável escolhida. Exemplo: 1. #include<iostream> 2. 3. using namespace std; 4. 5. int main (){ 6. 7. int numero; 8. 9. cin >> numero; 10. 11. return 0; 12. } Na linha 7 foi declarada a variável numero. Depois, na linha 9, foi feita a entrada de dados dessa variável. Assim, quando esse código for executado, o terminal abrirá e ficará a espera de um valor a ser digitado, como mostra a figura a seguir. Obs.: como é uma variável int, deve-se digitar apenas um valor numérico inteiro. Ao digitar o número e depois ‘Enter’, o número 6 passou a ficar gravado na variável numero, pois é essa variável que está no comando no cin. 17 4.1.1. Entrada de textos A entrada de dados em uma variável do tipo char pode ocorrer de duas formas: 1ª forma: 1. #include<iostream> 2. 3. using namespace std; 4. 5. int main (){ 6. 7. char nome[20]; 8. 9. cin >> nome; 10. 11. return 0; 12. } Depois de declarada a variável nome do tipo char (sempre lembrando de colocar a quantidade máxima de caracteres que serão utilizados), houve a entrada de dados dessa variável através do comando cin. Usando esse comando, mesmo que a pessoa digite duas ou mais palavras, só será salvo a primeira palavra dentro da variável. O comando cin salva todos os caracteres até encontrar um espaço ou uma quebra de linha (quando usa-se o ‘Enter’). 2ª forma: 1. #include<iostream> 2. 3. using namespace std; 4. 5. int main (){ 6. 7. char nome[20]; 8. 9. cin.getline( nome, 20); 10. 11. return 0; 12. } A entrada de dados na variável nome dessa vez foi feita com o comando cin.getline(). Esse comando só é usado na entrada de dados de variáveis do tipo char. A diferença dele para o cin é que o cin.getline() consegue pegar uma frase inteira. Ou seja, se forem escritas várias palavras, todas elas serão salvas na variável nome, contanto que estejam na mesma linha e a quantidade de caracteres seja menor do que a quantidade máxima colocada na declaração. A sintaxe do comando é a seguinte: dentro dos parênteses do cin.getline() deve-se colocar primeiro o nome da variável que receberá o texto digitado e depois a quantidade máxima de caracteres dessa variável. Resultando em: cin.getline(nome_da_variável, quantidade_máxima_de_caracteres); 18 4.1.1.1. Comando cin.ignore() O comando cin.ignore() deve ser usado sempre que houver uma entrada numérica e depois uma entrada de texto com o comando cin.getline(). Caso você se esqueça de usar o cin.ignore() nesses casos a variável char do cin.getline() receberá um “vazio” sem nem mesmo permitir a entrada de dados pelo usuário. Segue um exemplo de trecho de código onde é preciso usar esse comando: 1. int numero; 2. char nome[20]; 3. 4. cin >> numero; 5. cin.ignore(); 6. cin.getline(nome, 20); 4.2. Saída de dados São os dados que são mostrados ao usuário também pelo terminal. O comando usado será o cout (junção da letra ‘c’ referente a linguagem utilizada com a palavra em inglês ‘out’ que significa fora). O comando cout é acompanhado por dois sinais de menor ‘<<’. É interessante notar que os operadores << e >> indicam perfeitamente o sentido do fluxo. Ao fazer cin >> x de forma que o usuário entre com x, o fluxo vai do terminal para a variável, assim, terminal >> variável. Analogamente, ao fazer cout << x, nota-se que o fluxo vai da variável para o terminal, assim, terminal << variável. O comando cout exibe na tela valor de variáveis, constantes e textos. Exemplo: 7. #include<iostream> 8. 9. using namespace std; 10. 11. int main (){ 12. 13. int numero; 14. 15. cin >> numero; 16. 17. cout << numero; 18. 19. return 0; 20. } Esse código, como iniciado em exemplos anteriores, tem a declaração de uma variável do tipo int chamada numero. É feita, em seguida, a entrada de dados dessa variável. Logo em seguida faz-se a saída dessa variável, ou seja, é mostrado para o usuário, através do terminal de comandos, o valor que está salvo na variável numero. É possível ver na imagem a seguir como ficaria essa saída de dados. Inicialmente, como temos uma entrada de dados, devemos digitar um valor numérico inteiro para atribuir à variável numero. Nesse exemplo foi digitado o número 6. Em seguida está mostrando embaixo novamente o número 6. Isso ocorreu porque, depois da 19 entrada de dados (linha 15), tinha uma saída de dados (linha 17) da variável numero. Na saída também é possível mostrar uma mensagem ou frase, como no exemplo seguir: 1. #include<iostream> 2. using namespace std; 3. 4. int main (){ 5. 6. int numero; 7. 8. cin >> numero; 9. 10. cout << “O valor salvo foi:” << numero; 11. 12. return 0; 13. } Com essa saída, antes de mostrar o valor da variável numero, é mostrada a mensagem “O valor salvo foi:”. Tudo o que estiver entre aspas duplas ( “ ” ) dentro do comando cout é escrito na tela exatamente daquela forma.Caso o que esteja escrito na saída não esteja entre aspas duplas, será interpretado como uma variável e, caso ela exista, será exibido o valor nela armazenado. Isso acontece na saída da variável numero. 4.2.1. Comando endl O comando endl é exclusivamente usado em saídas de dados e sua função é fazer uma quebra de linha. O endl é a junção da palavra em inglês end + a primeira letra da palavra em inglês line, sendo assim a letra ‘l’. Ou seja, endl significa end line, do português final de linha. Portanto esse comando é responsável por finalizar uma linha da saída de dados. Veja no exemplo a seguir: 1. #include<iostream> 2. using namespace std; 3. 4. int main (){ 5. 6. cout << “Estudo no inatel”; 7. 8. return 0; 9. } 1. #include<iostream> 2. using namespace std ; 3. 4. int main(){ 5. 6. cout << “Estudo no inatel” << endl; 7. 8. return 0; 9. } 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. 6. cout << “Estudo no” << endl << “inatel” << endl; 7. 8. return 0; 9. } 20 Pode-se observar que o comando endl é usado para quebrar a linha atual e ir para a próxima, como fica claro quando colocamos o comando no meio da frase “Estudo no inatel” no último exemplo. 4.2.2. Comando setprecision Este comando requer o uso da biblioteca iomanip. Ele é usado exclusivamente na saída de dados e sua função é limitar e definir a quantidade de casas decimais que um valor real terá quando for mostrado na tela. A sintaxe do comando é a seguinte: cout << fixed << setprecision(número_de_casas_decimais); 1. #include <iostream> 2. #include <iomanip> 3. using namespace std; 4. 5. int main(){ 6. 7. double numero; 8. 9. cin >> numero; 10. 11. cout << fixed << setprecision(4); 12. cout << "Valor setado(com o comando setprecision) eh: " << numero << endl; 13. 14. return 0; 15. } O comando deve ser colocado antes da saída de dados que se deseja limitar a quantidade de casas decimais. No exemplo acima, a variável numero (do tipo double) recebeu um valor com 8 casas decimais e mostrou na saída (linha 12) o mesmo valor, só que com suas casas decimais fixadas com 4 dígitos, isso se deu por meio do comando setprecision que fixou a saída com uma precisão de 4 casas decimais. 21 5. Debug Debug (em português - depuração) é uma ferramenta muito utilizada entre os programadores para verificar os erros de lógica do código, uma vez que os erros de sintaxe (escrita) são identificados pelo próprio compilador. A IDE Falcon C++ nos possibilita um debugging de fácil entendimento auxiliando-nos na correção de possíveis erros, identificação de possíveis “bugs” do programa ou para simplesmente verificar toda a execução interna do seu programa. Tal procedimento pode ser feito através da seguinte maneira: Exemplo: Vamos supor que você está desenvolvendo um software que possui vários cálculos antes de apresentar o resultado final. Nota-se que tal resultado está saindo diferente do esperado. Com o Debug você pode analisar seu código linha a linha, acompanhando o que acontece com cada variável em tempo real. Assim será mais fácil perceber onde está o erro. - Após a criação do código, neste caso utilizaremos como demonstração um programa que efetuará a troca de dois valores que foram recebidos na entrada, seleciona-se a linha em que deseja-se iniciar a debugação do programa. Neste caso selecionamos a linha 5, logo abaixo da função principal, toda a linha ficará então vermelha. - Então executamos normalmente o programa (F9) e logo em seguida ativará os botões de debug na barra de ferramentas, que será descrito abaixo. - Tal seta serve para passarmos por dentro de alguma função extra, caso tenha, por ora não a utilizaremos. - Este botão será o mais usual durante o debugging, serve para percorrermos linha a linha do código a partir da linha 22 sinalizada em vermelho. É possível verificar onde está a execução do programa através da linha sinalizada em azul no código. - Por último, tal botão serve para sairmos da função em que entramos através da primeira seta. - Além disso, na aba direita da IDE é possível verificar todas as variáveis que foram criadas no programa e os valores que assumem ao longo do processamento. Neste caso os valores iniciais que toda variável assume, variáveis estas que não são inicializadas logo na declaração, são valores “lixo” (valores aleatórios que já estavam guardados na memória que foi alocada para tal variável), como pode ser visto na imagem ao lado. - Sendo assim, é necessário utilizar o comando “próximo passo (F7)” até que o programa chegue no fim da execução, lembrando que ao chegar na linha onde é esperado a entrada de dados é necessário ir para a tela do terminal de comandos do computador, que se abrirá automaticamente, e digitar então os valores de entrada do programa. Logo em seguida continuar com o comando F7, observando sempre a barra ao lado onde se encontra as variáveis do código. 23 - Dessa forma, ao encerrar o programa é possível verificar que os valores de entrada foram trocados e mostrados no terminal de comandos, e na barra de variáveis é possível verificar o valor que aux assume no final do execução. 24 6. Estruturas de Decisão Durante a execução de um programa, muitas vezes é necessário que sejam feitas escolhas caso determinado evento ocorra. É possível, através das estruturas de decisão, fazer este tipo de processamento. Podemos fazer qualquer tipo de comparação, como verificar se o usuário apertou determinada tecla, se um número é maior do que outro, etc. O processamento de uma estrutura de decisão sempre resultará em uma expressão lógica verdadeira (true) ou falsa (false). 6.1. A estrutura if-else 6.1.1. O comando if A estrutura mais utilizada para decisões é o if (se), conforme o código a seguir. 1. // verifica se a condição é verdadeira 2. if (condicao) 3. { 4. // e entra aqui caso seja. 5. } Note o uso de chaves após o comando if. Caso haja vários comando, seu uso é obrigatório. Mas se houver apenas um comando, as chaves podem ser omitidas. No caso abaixo, o uso de chaves é obrigatório: 1. if (condicao) 2. { 3. // comando 1 4. // comando 2 5. // ... 6. // comando n 7. } No caso abaixo, o uso de chaves é opcional (apesar de ser recomendado o uso das chaves em ambas situações): 1. if (condicao) 2. // único comando O if verifica se a condição é verdadeira, e caso seja, o código dentro da estrutura é executado. Para isto, temos vários operadores bastante utilizados:25 Note que é um erro fazer a expressão if (x = y), pois o = atribui o valor de y em x, enquanto if (x == y) compara se o valor de x é igual ao valor de y. Há também os operadores lógicos (&&, || e !), utilizados para verificar conectividade lógica entre duas ou mais condições. Com eles, podemos fazer uma tabela verdade, que demonstra a relação lógica dos operadores, tenhamos como exemplo duas variáveis (A e B) que serão combinadas de acordo com o operador lógico a fim de obtermos ou verdadeiro (true) ou falso (false): - Se tivermos duas variáveis ou duas condições que obrigatoriamente têm de serem satisfeitas para que os comandos de dentro da estrutura sejam executados, utilizaremos entre essas condições o operador lógico && pois só resulta em verdadeiro se ambas condições A e B forem verdadeiras. Exemplo: Só poderá efetuar a soma entre dois números se ambos forem positivos. 1. if (num1 > 0 && num2 > 0) 2. // efetua soma - Já se dentre as condições da minha estrutura if apenas uma delas necessita ser obrigatoriamente verdadeira, podemos utilizar o operador lógico || pois com ele se uma das condições/variáveis forem satisfeitas o resultado lógico da associação será verdadeiro, entrando então no bloco de comandos do if. Exemplo: Poderá efetuar a soma entre dois números se ao menos um deles for positivo. 26 1. if (num1 > 0 || num2 > 0) 2. // efetua soma - E ainda temos o operador lógico NAO (!) que é muito utilizado quando queremos negar nossa condição. Exemplo: Só poderá efetuar a soma entre dois números se o num1 não for maior que zero. 1. if (!(num1 > 0)) 2. // efetua soma Lembre-se que não é preciso decorar estas tabelas, basta analisar a lógica dos operadores lógicos. Assim como em operações matemáticas, operadores lógicos, aritméticos e relacionais também apresentam uma ordem de operações. 1. Aritmético (+, -, %, (), etc); 2. Relacional (=, *=, /=, +=, etc); 3. Não (!); 4. E (&&); 5. Ou (||); 6. Xou (Para expressões lógicas, pode ser simulado através de !=). Podemos memorizar a precedência dos operadores pela expressão ARNEOX. Desta forma, há uma diferença entre as seguintes expressões: if (true || true && false) // verdadeiro Verdadeiro e falso resulta em falso. Verdadeiro ou falso resulta em verdadeiro. if ((true || true) && false) // falso Verdadeiro ou verdadeiro resulta em verdadeiro. Verdadeiro e falso resulta em falso. Desta forma, podemos fazer algumas afirmações: if ((0 == 0) && (6 % 2 == 0)) // verdadeiro Como 0 é igual a 0 e o resto da divisão de 6 por 2 é 0, resulta em verdadeiro. if (!(8 == 9) || (9 < 2)) // verdadeiro 8 não é igual a 9, o que irá resultar em falso. Mas não (!) falso resultará em verdadeiro. 9 não é menor que dois, o que resulta em falso. Nisso, temos (verdadeiro ou falso), o que resulta em verdadeiro. if ((12 * 2 != 48 / 2) && (!false == (2 > 10))) // falso Temos que (12 * 2 != 48 / 2) resultará em falso, pois 24 é igual a 24. (1) 2 > 10 resultará em falso. (2) 27 Não falso (!false) resultará em verdadeiro. (3) Fazendo (2) == (3) resultará em falso. (4) Finalmente, (1) && (4) resultará em falso, pois teremos falso e falso. (5) As expressões lógicas podem também ser utilizadas com variáveis. O exemplo a seguir compara se duas variáveis são iguais, e mostra uma mensagem caso sejam: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x, y; 7. 8. cout << "Entre com dois valores:" << endl; 9. cin >> x >> y; 10. 11. // compara se x é igual a y 12. if (x == y ) 13. { 14. // esta mensagem aparecerá apenas se x for igual a y 15. cout << "x e y sao iguais." << endl; 16. } 17. 18. return 0; 19. } 6.1.2. O comando else Caso queiramos que o código execute um determinado trecho, caso a condição do if seja falsa, podemos utilizar o comando else (senão) para este caso. O código abaixo exemplifica o uso do else: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int num ; 7. 8. cout << "Entre com um valor: "; 9. cin >> num ; 10. 11. if (num % 2 == 0) // compara se num é par 12. { 13. // esta mensagem aparecerá apenas se num for par 14. cout << num << " eh par." << endl; 15. } 16. else // se num não for par, virá para cá 17. { 18. // esta mensagem aparecerá apenas se num não for par 28 19. cout << num << " eh impar." << endl; 20. } 21. 22. return 0; 23. } No exemplo acima, verificamos se o resto da divisão de num por 2 é igual a zero (num % 2 == 0), ou seja, se num é divisível por 2. Caso seja verdadeiro, então num é par. Caso contrário (num % 2 != 0), podemos afirmar que é ímpar. Assim, nota-se que toda vez que a condição do if for falsa, o else será automaticamente executado. É importante notar que um if não obriga o uso do else, entretanto, é necessário a existência de um if para que se tenha um else. 6.1.3. If-else aninhado Caso tenhamos um if-else dentro de um if ou dentro de um else, temos um if-else aninhado. Analise o exemplo abaixo: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int n; 7. cout << "Entre com n: "; 8. cin >> n; 9. 10. if (n % 2 == 0 ) 11. { 12. cout << "Par e " ; 13. if (n > 0 ) 14. { 29 15. cout << "positivo" << endl; 16. } 17. else 18. { 19. if (n == 0) 20. cout << "igual a zero" << endl; 21. else 22. cout << "negativo" << endl; 23. } 24. } 25. else 26. { 27. cout << "Impar e "; 28. if (n > 0 ) 29. cout << "positivo" << endl; 30. else 31. cout << "negativo" << endl; 32. } 33. 34. return 0; 35. } O código primeiro verifica se n é par (n % 2 == 0). Caso seja par, será mostrada a mensagem “Par e “. Caso contrário, será mostrada a mensagem “Impar e “. Depois é verificado se n é positivo (n > 0), negativo ou nulo. Perceba que caso n seja ímpar, não é testado se n é igual a 0, pois 0 é um número par. 6.1.4. If-else encadeado Caso tenhamos vários if-elses seguidos,de forma que se haja uma cadeia, teremos um if-else encadeado, como no exemplo abaixo: 1. if (condicao1) 2. comando1 ; 3. else if ( condicao2) 4. comando2 ; 5. else if ( condicao3) 6. comando3 ; 7. else 8. comando4 ; No exemplo, será executado o comando correspondente à primeira condição que seja verdadeira. Caso nenhuma condição seja verdadeira, comando4 será executado. Note que caso haja mais de uma condição verdadeira, será executada apenas a primeira condição verdadeira. Suponhamos que condicao1 e condicao3 sejam ambas verdadeiras. Como condicao1 foi a primeira a ser verdadeira, apenas comando1 será executado. Abaixo, temos um exemplo do uso do if-else encadeado: 30 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x; 7. cout << "Entre com x: "; 8. cin >> x; 9. 10. if (x < 0) 11. cout << "Negativo" << endl; 12. else if (x > 0 ) 13. cout << "Positivo" << endl; 14. else 15. cout << "Nulo" << endl; 16. 17. return 0; 18. } Se x é menor que 0, ele é negativo. Senão se x é maior que 0, ele é positivo. Senão, ele é nulo. Podemos encadear quantos else ifs forem necessários. Quando há uma cadeia de &&s em um if, se qualquer uma das condições for falsa, o if terá sua execução interrompida sem que as demais condições sejam testadas. Desta forma, o código abaixo: 1. if (c1 && c2 && c3 && ... && cn) 2. // comando É equivalente a: 1. if (c1) 2. if (c2) 3. if (c3) 4. ... 5. if (cn ) 6. // comando Analogicamente, podemos afirmar o mesmo para uma cadeia de ||s, caso qualquer condição seja verdadeira. Assim, o trecho abaixo: 1. if (c1 || c2 || c3 || ... || cn ) 2. // comando É equivalente a: 31 1. if (c1) 2. // comando 3. else if (c2 ) 4. // comando 5. else if (c3 ) 6. // comando 7. ... 8. else if (cn ) 9. // comando 6.2. Switch Uma outra estrutura de decisão é o switch, utilizado exclusivamente para fazer comparações de igualdade com uma única variável. O switch é normalmente utilizado para a criação de menus por ser mais elegante do que o uso de vários else ifs. É importante notar que o switch é capaz de apenas testar tipos fundamentais aritméticos, isto é, variáveis do tipo char, int, double etc. Desta forma, não se pode utilizar o switch para testar, por exemplo, uma string. Para utilizar, deve-se colocar a palavra-chave switch seguida da variável que deseja ser testada, entre parênteses: switch (variavel) e abrir um bloco (chaves). Dentro do bloco, coloca-se case valor:, onde valor é uma constante ou variável a ser testada. Depois dos dois-pontos (:), colocam-se os comandos a serem executados, e no final do case, um break. O switch pode ter ainda uma comparação opcional que testa se qualquer comparação anterior falhou. Para utilizá-la, basta colocar o default: O código abaixo exemplifica o uso do switch: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x; 7. cout << "Entre com um valor inteiro: "; 8. cin >> x; 9. 10. switch (x) 11. { 12. case 1 : // se x == 1 13. cout << "O valor 1 foi digitado." << endl; 14. break ; 15. 16. case 2 : // se x == 2 17. cout << "O valor 2 foi digitado." << endl; 18. break ; 19. 20. default: // se x != 1 e x != 2 32 21. cout << "Um valor diferente de 1 ou 2 foi digitado." << endl ; 22. break ; 23. } 24. 25. return 0; 26. } No código acima, é testada uma variável x. O switch verifica se ela é igual a 1 ou igual a 2. Caso seja, será executado o código de seu respectivo case. Caso um valor diferente de 1 ou 2 seja digitado, o default será executado. Desta forma, o código acima é equivalente ao código abaixo: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x; 7. cout << "Entre com um valor inteiro: "; 8. cin >> x; 9. 10. if (x == 1 ) 11. cout << "O valor 1 foi digitado." << endl; 12. else if (x == 2) 13. cout << "O valor 2 foi digitado." << endl; 14. else 15. cout << "Um valor diferente de 1 ou 2 foi digitado." << endl; 16. 17. return 0; 18. } Nota-se o uso do break em cada case e no default, mas para que serve ele? Caso o mesmo não seja colocado, os comandos de todos os cases abaixo dele serão executados até que um break será encontrado. O código abaixo exemplifica isto: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x; 7. cout << "Entre com um valor inteiro entre 0 e 5, inclusive: "; 8. cin >> x; 9. 33 10. switch (x) 11. { 12. case 5 : 13. cout << 5; 14. case 4 : 15. cout << 4; 16. case 3 : 17. cout << 3; 18. case 2 : 19. cout << 2; 20. case 1 : 21. cout << 1; 22. case 0 : 23. cout << 0 << endl ; 24. break; // será executado até aqui 25. default: 26. cout << "O valor deve estar entre 0 e 5." << endl; 27. break; 28. 29. } 30. return 0; 31. } Nota-se que foram mostrados todos os valores entre 4 e 0. Isto aconteceu devido à falta dos comandos break, fazendo que todos os cases a partir do 4 até o 0 fossem executados. Note que, caso não houvesse uma parada em 0, o default também seria executado. Podemos, ainda ter cases sem comando algum, de forma a encadear vários deles: 1. #include <iostream> 2. 3. using namespace std; 4. 5. int main() 6. { 7. int x; 8. cout << "Entre com um valor inteiro entre 0 e 5, inclusive: "; 9. cin >> x; 10. 11. switch (x) 12. { 13. case 5 : 14. case 3 : 15. case 1 : 16. cout << "Impar" << endl; 17. break ; // será executado até aqui 18. case 4 : 19. case 2 : 20. case 0 : 21. cout << "Par" << endl; 34 22. break ; // ou será executado até aqui 23. default: 24. cout << "O valor deve estar entre 0 e 5." << endl; 25. break ; 26. } 27. 28. return 0; 29. } Podemos utilizar das propriedades do switch para nossa vantagem de várias formasdiferentes. Analise o exemplo abaixo, que calcula o fatorial de um int x: 1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int x; 7. cout << "Entre com x (0 <= x <= 6): " ; 8. cin >> x; 9. 10. cout << x << "! = "; 11. switch (x) 12. { 13. case 6 : 14. x = x * 5 ; 15. case 5 : 16. x = x * 4 ; 17. case 4 : 18. x = x * 3 ; 19. case 3 : 20. x = x * 2 ; 21. case 2 : 22. cout << x << endl; 23. break ; 24. case 1 : // 0! = 1! = 1 25. case 0 : 26. cout << 1 << endl; 27. break ; 28. default: 29. cout << "Valor invalido!" << endl; 30. break ; 31. } 32. 33. return 0; 34. } 35 Um detalhe importante é que o switch não é uma estrutura de repetição, que será estudada no item 8. Assim, o switch é executado apenas uma vez, sendo necessária uma estrutura de repetição caso o valor deva ser testado várias vezes. 36 7. Abreviações Em programação cada vez nossos códigos tendem a ficar maiores com o passar do tempo com isso há a necessidade da inclusão de novas funcionalidades fazendo com que fique cada vez mais complexas as instruções. Um recurso muito utilizado para tentar diminuir esse problema é abreviar instruções. Exemplo 1: Somar + 1 na variável contador. 1. contador = contador + 1; 2. //ou 3. contador++; A seguir teremos uma tabela com algumas abreviações que podemos utilizar. Modo Normal Abreviado Descrição contador = contador + 1; contador++; Soma 1 unidade na variável contador total = total + numero; total += numero; Acrescenta na variável total o valor que a variável numero contém contador = contador – 1; contador--; Subtrai 1 unidade na variável contador a = a * b; a *= b; Multiplica o valor que a variável “a” contém pelo valor que “b” contém e atribui em “a” a = a / b; a /= b; Divide o valor que a variável “a” contém pelo valor que “b” contém e atribui em o quociente “a” a = a % b; a %= b; Retorna o resto da divisão de “a” por “b” e atribui o valor em “a” total = total - numero; total -= numero; Subtrai na variável total o valor que a variável numero contém Existem ainda abreviações referente a pós-incremento e pré-incremento. ● Pós-Incremento: Incremento++ 1. #include<iostream> 2. using namespace std; 3. int main() { 4. int total, numero = 5 ; 37 5. 6. total = numero ++; 7. cout << total; 8. } Neste exemplo a variável total será impressa com o valor de 5, pois primeiro será feito a atribuição da variável numero na variável total e depois incrementado 1 na variável numero. Por isso, damos o nome de pós-incremento. ● Pós-Incremento: Incremento-- 1. #include<iostream> 2. using namespace std; 3. int main() { 4. int total, numero = 5 ; 5. 6. total = numero --; 7. cout << total; 8. } Neste exemplo a variável total também será impressa com o valor de 5, pois primeiro será feito a atribuição da variável numero na variável total e depois decrementado 1 na variável numero. ● Pré-Incremento: ++Incremento 1. #include<iostream> 2. using namespace std; 3. int main() { 4. int total, numero = 5 ; 5. 6. total = ++numero; 7. cout << total; 8. } Neste exemplo a variável total será impressa com o valor de 6, pois primeiro será feito o incremento de 1 unidade na variável numero e depois a atribuição da variável numero na variável total. Por isso damos o nome de Pré-incremento. ● Pré-Incremento: --Incremento 1. #include<iostream> 2. using namespace std; 3. int main() { 4. int total, numero = 5 ; 5. 6. total = --numero; 7. cout << total; 8. } 38 Neste exemplo a variável total será impressa com o valor de 4, pois primeiro será feito o decremento de 1 unidade na variável numero e depois a atribuição da variável numero na variável total. 39 8. Estruturas de repetição Em alguns casos precisamos que um certo trecho de código seja executado mais de uma vez. Para que não seja necessário escrever esse pedaço do código várias vezes podemos usar uma estrutura de repetição que executará esse trecho o número de vezes que for determinado. Para ilustrar vamos imaginar a seguinte situação: Escrever na tela “Feliz aniversario!” 10 vezes. Se não fosse possível utilizar esse recurso na programação precisaríamos de 10 instruções para fazer isso, tornando nosso código maior do que necessário. Sem utilizar repetição: 1. cout << "Feliz aniversario!" << endl ; 2. cout << "Feliz aniversario!" << endl ; 3. cout << "Feliz aniversario!" << endl ; 4. cout << "Feliz aniversario!" << endl ; 5. cout << "Feliz aniversario!" << endl ; 6. cout << "Feliz aniversario!" << endl ; 7. cout << "Feliz aniversario!" << endl ; 8. cout << "Feliz aniversario!" << endl ; 9. cout << "Feliz aniversario!" << endl ; 10. cout << "Feliz aniversario!" << endl; Cada vez que um determinado trecho de código é executado dizemos que ocorreu um ciclo, uma volta ou um laço. Assim se o pedaço repetir 3 vezes dizemos que foram executados 3 laços. Exemplo 1: Imagine que você tenha que colocar objetos dentro de uma caixa. Os passos para isto seriam: 1º abrir a caixa; 2º verificar se existem objetos para colocar na caixa; 3º se existir, pegar um objeto; 4º colocar o objeto dentro da caixa; 5º verificar se existem objetos para colocar na caixa; 6º se existir, pegar um objeto; 7º colocar o objeto dentro da caixa; 8º verificar se existem objetos para colocar na caixa; 9º se existir, pegar um objeto; 10º colocar o objeto dentro da caixa; 11º verificar se existem objetos para colocar na caixa; 12º se não existir; 13º fechar a caixa; Repare que os 2º, 3º e 4º passos são idênticos aos passos seguintes, ou seja, até que acabe de colocar todos os objetos dentro da caixa os passos irão se repetir. Pensando em termos de código fonte, logo vemos que os 2º, 3º e 4º passos fazem parte de um bloco. Assim identificamos tudo que o precisamos para criar uma repetição: O que e até quando irá se repetir. ● O que: são as instruções que irão se repetir; ● Até quando: o que deverá acontecer para o que o mesmo pare de repetir. 40 Muitos dos erros encontrados hoje em softwares ocorrem devido a uma má escolha dessa condição de parada, fazendo com que o sistema entre em o que chamamos de “Loop Infinito”. Embora não seja uma regra obrigatória, antes de começar uma estrutura é indicado que as variáveisque forem usadas na dentro do trecho estejam todas criadas e inicializadas, pois assim garantimos que nenhuma variável entre com valores considerados “lixo”. Curiosidade: Para uma estrutura de repetição que guarda uma soma costumamos inicializar a variável com 0, mas caso a variável seja utilizada para fazer uma multiplicação é indicado que esse valor inicial seja 1, pois se a variável estiver com 0 sua multiplicação retornará um valor 0 multiplicado por qualquer outro valor. Essa dica é utilizada para que a mesma não venha apresentar um valor impreciso (lixo) no final da aplicação. Existem 3 tipos de estruturas de repetição: 8.1. While A estrutura de repetição while executa todas as instruções do laço enquanto a condição for verdadeira. É uma estrutura pré-testada, ou seja, quando na execução o programa encontrar uma estrutura de repetição, será feito um teste para ver se a condição de existência é verdadeira ou não. Se for verdadeira serão executados todos os comandos e ao final voltará para a condição de existência para repetir todo processo, isso acontecerá enquanto a condição retornar verdadeiro. Caso a condição retorne falso o programa sairá da execução da estrutura passando para a próxima instrução após a estrutura, continuando a execução do programa normalmente. Sintaxe: 1. while(condicao ){ // enquanto condicao for verdadeira 2. // executa instruções 3. } Como no bloco if-else, caso a estrutura possua somente uma instrução não é necessário o uso de chaves para início e fim. Colocamos entre os parênteses a condição que queremos para que a estrutura se repita. Exemplo 2: contar de 1 até 10 na tela utilizando repetição: 1. #include<iostream> 2. using namespace std; 3. 4. int main() { 5. int contador; 6. 7. // valor inicial da variável 8. contador = 1; 9. 10. // condição para a repetição 11. while(contador <= 10) { 12. 13. cout << contador << endl ; 14. contador++ ; //acréscimo de 1 na variável contador (incremento) 41 15. } 16. 17. cout << "Fim do while"; 18. } Observe que caso quiséssemos aumentar o intervalo do contador basta alterar a linha em que informamos a condição para o while. O trecho do código delimitado pelo uso das chaves na estrutura while se manteve em repetição enquanto que sua expressão retornava uma resposta “verdadeira”, uma vez que a estrutura recebe como resposta “falso” ela irá finalizar a repetição e continuar o código a partir daí. Em nosso exemplo a próxima instrução é um comando de escrita na tela dizendo “Fim do while”. Curiosidade: Enquanto a variável contador estiver valendo até 10 a execução estará restrita a somente dentro do bloco de instruções while. Portanto quando a variável receber um valor maior que 10 ela sairá. Nesse exemplo o valor que ela conterá ao sair da estrutura será 11. Exemplo 3: Escrever na tela as letras do alfabeto de A até J: 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. char letra ; 6. letra='A'; 7. 8. while(letra<='J'){ 9. cout << letra << endl; 10. letra++; 11. } 12. } Neste exemplo tivemos 2 curiosidades interessantes que é importante explicar com mais detalhes. ● Quando utilizamos caracteres alfanuméricos (letras principalmente) com apenas 1 caractere devemos colocá-los entre aspas simples; ● A letra quando passada para o computador é convertida em um número, para saber mais pesquise sobre a tabela ASCII. Por isso, quando mandamos acrescentar mais 1 na variavel char ele vai para a próxima letra. 42 Exemplo 4: Neste código vamos pedir que o usuário digite alguns valores e vamos somar os valores digitados e exibir a soma deles quando o usuário finalizar a digitação. Fazendo uma analogia com o exemplo 1, os objetos são os valores digitados e colocar esses objetos na caixa seria o mesmo que somá-los. Mas como iremos saber que o usuário não pretende mais digitar nenhum valor? Em programação utilizamos de um artifício que indica ao software se ele deve continuar a repetição ou finalizar a mesma (desativar o laço). Esse artifício recebe o nome de flag. Em nosso exemplo criaremos a seguinte situação: Se o usuário digitar o valor zero ele deseja parar de somar valores e para qualquer valor diferente será somado. 1. #include<iostream> 2. 3. using namespace std; 4. 5. int main(){ 6. double valor, total = 0; 7. 8. cout << "Digite um número (0 para sair): "; 9. cin >> valor; 10. 11. while(valor!=0 ){ 12. total = total + valor; 13. cout <<"Resultado parcial: "<<total<<endl; 14. 15. cout << "Digite um número (0 para sair): "; 16. cin >> valor; 17. } 18. 19. cout << "Resultado final: "<< total<<endl; 20. } Exemplo 5: Vamos imaginar que estamos criando um aplicativo para cadastrar e listar pessoas. Onde o usuário escolha a opção que deseja. 43 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int opcao; 6. opcao=- 1; 7. 8. while(opcao!=3 ){//início da estrutura de repetição 9. 10. cout << "Digite 1 para Cadastrar" <<endl; 11. cout << "Digite 2 para Listar"<<endl; 12. cout << "Digite 3 para Sair"<<endl; 13. cout << "Opcao: " ; 14. cin >> opcao; 15. 16. switch (opcao){ 17. case 1 : //opções do cadastro 18. break ; 19. case 2 : //listagem 20. break ; 21. case 3 : cout <<"Saindo do aplicativo"; 22. break ; 23. default: cout << "Opção Invalida"; 24. break ; 25. }//fim da estrutura de decisão 26. 27. } //fim da estrutura de repetição 28. } Note que inicializamos a variável opcao antes da estrutura de repetição para evitar que a variável seja criada com o valor “lixo” 3 e consequentemente nao venha a entrar no while. Podemos utilizar operadores “&&” , “||” e “!” igual temos na estrutura de decisão dentro da expressão das estruturas de repetição. Exemplo 6: Um algoritmo onde o usuário deva escolher um número entre 1 e 10. 1. #include<iostream> 2. using namespace std; 3. int main() { 4. int numero ; 5. 6. cout << "Digite um número entre 1 e 10: "; 7. cin >> numero; 8. 9. while(numero < 1 || numero > 10) { 10. cout << "Número Invalido!" << endl; 11. cout << "Digite um número entre 1 e 10: "; 12. cin >> numero ; 13. } 14. } 44 8.2. Do-While O funcionamento do do-while é bem parecido com o while diferenciando-se apenas da ordem como as coisas acontecem. Na estrutura while primeiro era testada a condição e se fosse verdadeira os comandos internos eram executados. Já com o do-while primeiro se executa os comandos e depois verifica-se se a condiçãoé verdadeira, caso seja os comandos são novamente executados. Sendo assim deve-se ter em mente que a estrutura do-while sempre irá executar pelo menos uma vez os comandos do bloco da estrutura. Resumindo: tudo aplicado ao while se aplica ao do-while, somente com a diferença que um é pré-testado (while) e o outro é pós-testado (do-while). O do-while é bastante usado em críticas de dados, pois o usuário entrará com uma determinada informação e cabe ao programa verificar se essa informação pode ser aceita ou se o usuário deverá entrar novamente com esse dado. Quando utilizamos para essa finalidade não é possível saber quantas vezes ele será repetido pois dependerá de valores que o usuário digitar. 1. do{ 2. //instruções 3. }while(condição de parada ); Exemplo 1: Em um código que recebe a idade de algumas pessoas não pode-se confiar que todos usuários responderão de maneira correta, mas o programador pode minimizar a chance de se obter um valor indesejado/inválido usando a crítica de dados. Uma crítica de dados é basicamente pedir para que a pessoa digite novamente a informação caso a entrada anterior não seja válida. 45 Em pseudocódigo: 1. repita 2. escreva "Idade (em anos)"; 3. leia idade ; 4. até(idade >= 0 e idade < 150 ); Em C++: 4. #include<iostream> 5. using namespace std; 6. 7. int main(){ 8. 9. int idade; 10. 11. do{ 12. cout <<"Idade (em anos):"; 13. cin >> idade; 14. }while( idade < 0 || idade >= 150); 15. 16. cout << "Sua idade é: "<<idade <<" anos"; 17. } No código acima colocamos a condição contrária a que gostaríamos que a variável idade tivesse para que, sempre que o usuário entrar com um valor indesejado a estrutura repita e peça novamente a entrada de dados. Exemplo 2: Também é possível colocar mensagens de erro para que o usuário saiba que o valor não foi aceito por tal motivo. Utilizamos estrutura de decisão para isso. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. int idade; 5. 6. do{ 7. cout <<"Idade (em anos):"; 8. cin >> idade; 9. 10. if( idade < 0 || idade > 150 ) 11. cout <<"Valor Incorreto. Digite um valor no intervalo de 0 ate 150"<<endl; 12. 13. }while( idade < 0 || idade > 150); 14. 15. cout << "Sua idade e: "<<idade <<" anos"; 16. } 46 Exemplo 3: Um artifício muito útil e seguido por muitos programadores é criar uma forma de aproximar pseudocódigo com programação. Como já vimos em assuntos anteriores temos o operador NÃO “!” que torna a informação contrária do que é, ou seja, se gostaríamos que o do-while saísse quando a expressão lógica fosse verdadeiro e repetisse quando fosse falso utilizamos ele na frente de toda expressão. Para garantir que tudo a seguir esteja relacionado com o “!” coloque a expressão entre parênteses. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. int idade; 5. 6. do{ 7. cout <<"Idade (em anos):"; 8. cin >> idade; 9. 10. if( idade < 0 || idade > 150 ) 11. cout <<"Valor Incorreto. Digite um valor no intervalo de 0 até 150"<<endl; 12. 13. }while( !(idade >= 0 && idade <= 150)) ; 14. 15. cout << "Sua idade é: "<<idade <<" anos"; 16. } Assim obtemos o mesmo resultado do anterior mas de uma maneira mais fácil de identificar. Note que podemos ler claramente que o valor deve estar entre 0 e 150, incluindo o zero. Exemplo 4: Contando de 1 até 10. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. int valor = 1 ; 5. 6. do{ 7. cout << valor << endl ; 8. valor ++; 9. 10. }while (valor<=10) ; 11. cout << "Valor final: "<<valor<< endl; 12. } 47 Curiosidade: Enquanto a variável valor estiver valendo até 10 a execução estará restrita a somente dentro do bloco de instruções do-while. Portanto quando a variável receber um valor maior que 10 ela sairá. Nesse exemplo o valor final impresso será 11. Exemplo 5: Utilizando o mesmo exemplo do while, criaremos um menu agora utilizando o do-while utilizando uma variável do tipo char. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. char opcao; 5. 6. do{//início da estrutura de repetição 7. 8. cout << "Digite C para Cadastrar"<<endl; 9. cout << "Digite L para Listar"<<endl ; 10. cout << "Digite S para Sair" <<endl; 11. cout << "Opcao: "; 12. cin >> opcao; 13. 14. switch(opcao){ 15. case 'C': //opções do cadastro 16. break ; 17. case 'L': //listagem 18. break ; 19. case 'S': cout <<"Saindo do aplicativo" ; 20. break ; 21. default: cout << "Opção Invalida" ; 22. break ; 23. }//fim da estrutura de decisão 24. 25. }while (opcao != 'S') ; 26. //fim da estrutura de repetição 27. } 8.3. For É uma estrutura pré-testada e normalmente a utilizamos quando sabemos o número de vezes que teremos que repetir um determinado pedaço de código. O princípio de funcionamento do for é bem parecido com o while, onde a repetição se manterá enquanto a condição de existência for verdadeiro, uma vez que essa condição retorne falso, a execução da repetição é interrompida e a próxima instrução é chamada. Em modo padrão, dentro dos parênteses devemos informar 3 parâmetros, que são eles: o valor inicial que será começada a contagem, o valor final da contagem e quantas unidades a estrutura percorrerá a cada ciclo de repetição. Se a estrutura começar com um valor mais baixo e ir aumentando ao longo do tempo até um valor mais alto dizemos que a variável contadora esta possuindo um incremento. Mas também a variável pode começar de um valor mais alto e ir decrementado até um valor mais baixo. 48 Seu funcionamento é o seguinte: 1. Inicia a variável reservada para contagem (no 1° parâmetro), essa será a única vez que será utilizado esse parâmetro. 2. Verifica se a condição criada no 2° parâmetro retorna verdadeiro ou falso. 3. Se retornar falso, a repetição é interrompida. 4. Caso seja verdadeiro, é executado todo o bloco de comandos dentro da estrutura. 5. Utiliza-se o 3° parâmetro para incrementar/decrementar a variável. 6. Repete a partir do passo 2. Sintaxe: ● Em pseudocódigo: 1. para inicio até fim passo incremento|decremento faça 2. Inicio 3. //bloco de instruções 4. Fim; ● Em C++: 1. for(inicio ; fim ; incremento | decremento){ 2. //bloco de instruções 3. } Observação: Para se construir um for o mínimo de informações que o mesmo deve conter é: 1. for( ; ; ) Jamais esqueça os 2 separadores dos parâmetrosdentro do for que são “;”, ou você terá problemas ao compilar seu código. Exemplo 1: (Incremento) Criaremos um contador que vá de 1 até 10. 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int contador; 6. 7. for(contador=1 ; contador <=10 ; contador = contador + 1){ 8. cout << contador<<endl; 9. } 10. return 0; 11. } 49 Exemplo 2: (Decremento) Criaremos um contador que vá de 10 até 1. 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int contador; 6. 7. for(contador=10; contador>=1 ; contador--){ 8. cout << contador<<endl; 9. } 10. return 0; 11. } Note que a diferença entre os exemplos está somente em uma linha (7). Para a estrutura de repetição for reservamos uma variável para ser nossa contadora. Ela será utilizada para verificar se deve se feito mais um ciclo ou não. Exemplo 3: Criaremos um software onde seja lido a idade de 50 pessoas e ao final diga qual a idade da mais velha. 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int idade, idademv=0; 6. 7. for(int i= 0; i < 50 ; i++){ 8. cout << "Digite a idade da "<<i+1 <<" pessoa: "; 9. cin >> idade; 10. if( idade > idademv){ 11. idademv = idade; 12. } 13. } 14. cout << "A pessoa mais velha possui "<<idademv << " anos."<<endl; 15. return 0; 16. } No exemplo utilizamos uma variável idade para ler a idade de cada pessoa e a variável idademv para guardar a idade da pessoa mais velha. Note que inicializamos a variável idademv com 0 para que nenhum lixo de criação de variável viesse a comprometer o software. É possível também adicionar uma estrutura de repetição dentro de outra. Exemplo 4: Utilizaremos o mesmo exemplo anterior mas agora obrigando o usuário a digitar valores maiores ou iguais a 0. Para isso utilizaremos o do-while. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. int idade, idademv=0; 50 5. for(int i= 0; i < 50 ; i++){ 6. 7. do{ 8. cout << "Digite a idade da "<<i+1<<" pessoa: "; 9. cin >> idade; 10. }while (!(idade>=0 )); 11. 12. if( idade > idademv) 13. idademv = idade; 14. } 15. cout << "A pessoa mais velha possui "<<idademv << " anos."<<endl; 16. return 0; 17. } Podemos adicionar operadores nos parâmetros do for. Exemplo 5: Um software que escreve na tela somente números pares de 0 até 10. 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. 5. for(int i= 0;i<=10 ;i= i + 2){ 6. cout << i <<endl; 7. } 8. } Exemplo 6: Deseja-se que seja criada uma sequência onde o próximo valor é a metade do anterior (somente valores inteiros). Valor Inicial: 100 1. #include<iostream> 2. using namespace std; 3. int main(){ 4. 5. for(int i= 100; i> 0; i = i /2){ 6. cout << i << endl ; 7. } 8. } 8.4 Loop Infinito Não é um assunto abordado pela matéria, mas em alguns casos precisamos criar estruturas que irão se repetir “eternamente”. Como por exemplo: O software presente em um portão eletrônico onde ele deve se manter executando a espera de um comando enquanto ele estiver ligado a tomada. 51 Uma das formas de se obter esse tipo de resultado é utilizar um número positivo no espaço reservado a condição de sua estrutura. Assim o número será compreendido pelo sistema como uma condição verdadeira (true) e executará o bloco de comandos dentro da estrutura. 1. while( 1){ 2. //instruções 3. } É possível adaptar essa maneira para que ela possua um fim como por exemplo um contador que comece em 1 e vai até 10. 1. #include<iost ream> 2. using namespace std; 3. 4. int main(){ 5. int contador =0; 6. 7. while (1){ 8. contador ++; //soma-se +1 na variável contador 9. cout << contador << endl; 10. 11. if(contador ==10) 12. break; 13. } 14. } Observe que foi utilizado uma estrutura de decisão para terminar a estrutura de repetição. A instrução break assim como no switch tem a função de parar a repetição. Alguns programadores utilizam-se sempre desse artifício por acharem mais fácil o entendimento e uma possível manutenção posterior caso necessário. Esse artifício também está presente nos outros tipos de repetição estudados. Utilizando-se do mesmo exemplo: Com for: 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int contador =0; 6. 7. for(;;){ 8. contador ++; //soma-se +1 na variável contador 9. cout << contador << endl; 10. 11. if(contador ==10) 12. break; 13. } 14. } 52 Para o caso do for não é preciso acrescentar nada, somente a própria estrutura já possui esse recurso. Enquanto que no while e do-while é obrigatório que se coloque algo entre o parêntese. Com Do-While: 1. #include<iostream> 2. using namespace std; 3. 4. int main(){ 5. int contador =0; 6. 7. do { 8. contador ++; //soma-se +1 na variável contador 9. cout << contador << endl; 10. 11. if(contador ==10) 12. break; 13. 14. } while(1 ); 15. } 8. Vetores Um vetor nada mais é do que uma variável composta unidimensional, formada por uma sequência de variáveis, todas do mesmo tipo de dados, com o mesmo identificador (mesmo nome) e alocadas sequencialmente na memória. 53 8.1. Declaração Imagine que você está desenvolvendo um programa para computar a idade de todos os seus colegas de classe, ficaria inviável fazer várias variáveis do tipo int, uma para cada colega, a fim de coletar todas as idades. No entanto você sabe que todas as idades sempre serão do tipo inteiro, dessa forma você pode criar um vetor do tipo int e armazenar nele todas as idades. Já que um vetor pode guardar várias variáveis do mesmo tipo de dados, temos então que definir quantos valores do tipo especificado ele deve guardar, para que ele possa reservar esse espaço na memória. Dessa forma seguimos 3 passos para a declararmos um vetor: - Especificar o tipo de dados que ele irá guardar: int, double, float, char… - Definirmos o nome da variável (lembrando que é aconselhável utilizar um nome que faça ligação ao que será guardado no meu vetor). - E por fim, especificar o tamanho máximo do meu vetor, quantas variáveis do tipo especificado será utilizada, através de colchetes: [ 30 ], [ 100 ], [ 5 ] ... tipo_de_dado Nome_da_variável [tamanho]; int idades [27]; No entanto, uma vez que as variáveis armazenadas no vetor tem o mesmo nome, o que
Compartilhar