Enviando dados para Funções em C++ - Parâmetros e Argumentos

Neste tutorial, vamos aprender como enviar dados para as funções, em linguagem de programação C++.

Enviando Dados para Funções

No tutorial passado, de nosso curso de C++, aprendemos como as funções retornam informações para quem as invocou, através do comando return.

As funções podem receber informações através do uso de parâmetros, que é uma variável especial, declarada no cabeçalho da função, que ficará responsável por armazenar os valores que serão passados para estas funções. Esses valores são os argumentos.

Para usarmos os argumentos (ou seja, passarmos algum valor para funções trabalharem), devemos informar a lista de parâmetros, dentro dos parêntesis da declaração da função.

Por exemplo, uma função que retorna um inteiro, recebe um inteiro e se chama func, se declara assim:

  • int func(int var) { ... }


Para invocar, passando o número 2112, por exemplo, fazemos:

  • func(2112);


var é o parâmetro, já 2112 é um argumento.

Agora uma função que não retorna nada, se chama func2 e recebe um inteiro, um float e um booleano:

  • void func2(int var, float num, bool status) { ... }


Se quisermos passar o inteiro 1, o float 21.12 e o booleano true, para dentro desta função, fazemos:

  • func2(1, 21.12, true);


Lista de parâmetros: var, num e status
Argumentos (valores): 1, 21.12 e true

Veja a ordem: um inteiro, um float e um booleano! Respeite a ordem da lista de parâmetros do cabeçalho da função!

Exemplo de parâmetros e argumentos em C++

Vamos criar uma função que recebe um número qualquer, e retorna ele ao quadrado:
#include <iostream>
using namespace std;

float quadrado(float num)
{
    return num*num;
}

int main()
{
    float var;

    cout<<"Numero para elevar ao quadrado: ";
    cin >> var;

    cout<<var<<"*"<<var<<" = " << quadrado(var)<<endl;
}
Note que passamos a variável var, que é um float, para a função quadrado(), que recebe um float como argumento.

Embora tenhamos passado a variável var, o que acontece na verdade, por debaixo dos panos, é que passamos um número, um valor, que foi digitado pelo usuário.

Se passarmos var = 5, o que vai pra função é 5.
É como se tivéssemos feito: quadrado(5);

Dentro da função, esse valor é armazzenado no parâmetro num, ok?
A função não 'vê' a variável var, nem sabe de sua existência, só pega seu valor e copia para a variável float num.

Parâmetros e Argumentos em C++

Vamos agora criar uma função que recebe um número, eleva ele ao cubo e retorna esse valor.
#include <iostream>
using namespace std;

float cubo(float num)
{
    num = num*num*num;

    return num;
}

int main()
{
    float num;

    cout<<"Numero para elevar ao cubo: ";
    cin >> num;

    cout<<"Numero informado: "<<num<<endl;
    cout<<"Cubo: "<< cubo(num)<<endl;
    cout<<"Valor de num: "<<num<<endl;
}
Fizemos um teste nesse exemplo.
O parâmetro é num, dentro da função.
Ao invocar a função, também passar uma variável de nome num.

Dentro da função, alteramos o valor de num.
Antes, era num, depois passa a ser (num*num*num), e retornamos esse novo valor de num.

Na main(), vamos exibir o número que o usuário digitar (num), o cubo (invocando a função cubo() ), e depois exibimos novamente o valor de num.

Para num=4, o resultado é:
Como passar um argumento em uma função no C++

Note que o valor de num foi alterado SOMENTE dentro da função!
Quando passamos um argumento pra uma função, a função faz uma cópia dele e atribui ao parâmetro específico. Dentro da função, você alterou o valor do parâmetro, a variável num original, não é alterada!

Ah...agora você já consegue entender um pouco mais a main():
int main(){
...
   return 0;
}

Ou seja, ela é uma função que não recebe nenhum argumento (pois não tem parâmetro) e retorna um inteiro, no caso, ela retorna 0.

Dois adendos:

  1. Universalmente, quando uma função retorna 0, é porque deu tudo certo, tudo ok. Quando seu código funcionar ok, deverá retorna 0
  2. Nesse caso específico, a main() não tem parâmetros, mas tem versões dela recebendo argumentos sim, veremos mais adiante em nosso curso

Como Receber Informações de uma Função - O comando RETURN em C++

Agora que você já aprendeu o que são e para que servem as funções, vamos ver aprender como nos comunicar com as funções, recebendo dados e informações delas através do comando return.

Trocando dados com funções em C++

No tutorial anterior, de nossa seção de Funções em C++, vimos como criar e invocar uma função.
Bastou chamar pelo nome: hello(), que ela veio rapidinho e executou de imediato.

Poderíamos chamar 1 milhão de vezes, que ela executaria 1 milhão de vezes, sem precisar ficar repetindo código, basta invocar a função sempre que precisarmos fazer aquilo que ela se propõe a fazer.

Mas ali tem um problema...quando invocamos uma função, a execução sai do local onde houve a chamada e vai pra outro local da memória, onde estão as instruções da função, executa tudo, e volta. Nesse caso anterior, não há uma comunicação entre quem chamou e a função.

Vamos ver um código C++ onde invocamos uma função que pede o número e exibe seu dobro:
#include <iostream>
using namespace std;

void doub()
{
    float num, dobro;

    cout<<"Digite um numero: ";
    cin >> num;

    dobro = 2*num;

    cout<<"Dobro: "<<dobro<<endl;

}

int main()
{
    doub();
    return 0;
}
Legal, né? Porém, a gente não tem acesso a essa informação 'dobro', não podemos pegar ela pra usar em outro cálculo, por exemplo, ele é simplesmente exibido dentro da função e ao término dela, esse valor se perde. As variáveis internas das funções são criadas localmente, e depois excluídas.

Se tentar usar 'dobro' fora da função vai ver que dá um erro de compilação.
Precisamos achar outra maneira de fazer a função se comunicar com o exterior, de enviar informações pra fora, concorda que isso é importante?

O comando RETURN em Funções

Sempre que quisermos enviar uma informação de dentro de uma função para o local onde ela foi chamada, usamos o comando return.

Primeiro, no cabeçalho de declaração da função, precisamos informar o tipo de dado que a função vai retornar. No exemplo anterior é void porque ela não retorna nada.

Se o tipo de dado que ela vai retornar é um float, por exemplo, seu cabeçalho deve ser:
float doub() {...}

E dentro do escopo da função devemos fazer: return info;
Onde info deve ser um float.

Pronto, a informação 'info' será retornada, devolvida para o local onde a função foi invocada.
Vamos criar uma função que pede um número, dobra ele e retorna seu dobro:
#include <iostream>
using namespace std;

float doub()
{
    float num, dobro;

    cout<<"Digite um numero: ";
    cin >> num;

    dobro = 2*num;

    return dobro;
}

int main()
{
    float res;
    res = doub();

    cout<<"Dobro: "<<res<<endl;
    return 0;
}
Agora, quando chamamos a função: doub()
Um valor é retornado para quem chamou ela, volta um float, no caso.

Então armazenamos o resultado desse retorno na variável res (obviamente, deve ser float):
res = doub();

E prontinho, essa variável vai ter dobro do valor que o usuário digitar lá dentro da função.
Podemos até deixar o código mais enxuto, veja:
#include <iostream>
using namespace std;

float doub()
{
    float num;

    cout<<"Digite um numero: ";
    cin >> num;

    return (2*num);
}

int main()
{
    cout<<doub()<<endl;
    return 0;
}

Veja que podemos dar return numa expressão, diretamente: return 2*num;

Exemplo de uso de RETURN em Funções

Vamos agora criar uma função de par ou ímpar.
Se for par, ela deve retornar 0, se for ímpar deve retornar 1.

Veja como fica nosso código C++:
#include <iostream>
using namespace std;

int par_impar()
{
    int num;

    cout<<"Digite um numero: ";
    cin >> num;

    if(num%2==0)
        return 0;
    else
        return 1;
}

int main()
{
    if(par_impar()==0)
        cout<<"É par!\n";
    else
        cout<<"É ímpar!\n";
    return 0;
}
Note agora que tem dois comandos return dentro da nossa função par_impar(), isso pode, mas veja que somente um ou outro pode acontecer, nunca um IF e um ELSE é executado, é sempre um deles.

Vamos dar uma enxugada nesse código?
#include <iostream>
using namespace std;

int par_impar()
{
    int num;

    cout<<"Digite um numero: ";
    cin >> num;

    return (num%2);
}

int main()
{
    if(!par_impar())
        cout<<"É par!\n";
    else
        cout<<"É ímpar!\n";
    return 0;
}
Conseguiu entender de boa?

Boas práticas de funções

Primeiro, nomes de funções: não existe um jeito certo nem errado de usar, mas recomendamos ser consistentes com o nome delas.

De preferência crie funções com o nome no seguinte estilo: c_progressivo(), projeto_progressivo(), van_der_graaf_generator() ... - tudo minúsculo, separado por _
Ou: cProgressivo(), projetoProgressivo(), vanDerGraafGenerator()...- primeira letra minúscula, e maiúscula para início das próximas palavras, ok?

Segundo, use muitas funções, e faças elas bem comunicativas, sempre que possível retornando e recebendo (vamos ver no próximo tutorial) dados, de maneira bem lógica e clara.

Assim como cada peça do seu carro ou cada órgão do seu corpo faz sua tarefa específica, eles também se comunicam e trocam informações entre si, isso é essencial para o bom funcionamento do sistema.

As funções de um sistema devem fazer o mesmo! Isso é uma boa prática de programação, não se esqueça! Faça suas funções serem facilmente 'acopladas' com outras funções, isso vai ser essencial para você ser capaz de criar sistemas grandes e robustos, como softwares empresariais, sistemas operacionais, jogos, etc.

Função em C++ - O que é, Como funciona e Como criar e usar ?

Neste tutorial, daremos início ao estudo das Funções em C++, onde iremos aprender:
  • O que é uma função?
  • Para que serve uma função?
  • Como criar uma?
  • Como usar uma função?

Função em C++: O que é e Para que serve

Você já viu uma placa de algum hardware, como a placa do seu computador, ou as peças internas de uma televisão, celular...é mais ou menos assim:

O que é uma função

Veja: não existe somente uma peça responsável por fazer tudo.
Um placa é uma porção de pecinha fazendo pequenos trabalhos, bem específicos.

Como fazem coisas bem específicas, como contar ou medir a temperatura, por exemplo, podemos usar essas pecinhas em outras placas, como a de um carro ou de uma geladeira.

Ou seja, cada pecinha dessas tem uma função, específica, faz algo.
Em programação C++, é a mesma coisa: função é um treco que faz uma coisa específica.

Explicando melhor, função é um bloco de código, com alguns comandos de C++ dentro, que faz determinada tarefa. Uma função pode receber e retornar informações para quem chamou a função.

É muito melhor, mais eficiente, mais rápido e mais viável de criar uma placa com diversas pecinha, fazendo coisa específicas, do que uma peçona fazendo algo sozinha.

Da mesma maneira, não é nada viável ter um único bloco de código gigante, de milhares de linhas, pois seria extremamente difícil de trabalhar com ele, saber onde está havendo erros, onde está cada coisa...o ideal é ir quebrando seu programa em programinhas menores, que fazem coisas mais específicas e fáceis de serem entendidas.

É como se cada função fosse uma pecinha de lego. Você vai juntando as peças e vai montando coisas grandes e bacanas. Seu sistema operacional, por exemplo, funciona assim.

Vamos aprender como criar uma função?

Como criar uma função em C++

A sintaxe do código para criar uma função é a seguinte:
tipo nome(lista_parametros)
{
    // código da
    // função

    return algo;
}
As funções podem ou não retornar alguma informação, como um inteiro ou um float.
Por exemplo:
int function1() {...} - retorna um inteiro
float function2() {...} - retorna um float
void function3() { ... } - não retorna nada

Dentro dos parêntesis, ela podem receber informações para trabalhar com esses dadis, são os parâmetros:
void function1(int num) {...} - Envia um inteiro para a função e não retorna nada
int function2(int num1, float num2) {...} - Envia dois números como parâmetro, um inteiro e um float, e retorna um inteiro.

Se a função retorna algum tipo de dado, usamos o return dentro do bloco de código, para retornar o tipo de dado que declaramos no cabeçalho da função.

Vamos criar a função hello(), ela não retorna nenhum dado e não recebe nenhuma informação, apenas imprime o hello, world! na tela:
void hello()
{
    cout <<"Hello, world!\n";
}

Como chamar e usar uma função

Para chamar a função basta escrever o nome dela, seguido de parêntesis e com as informações que ela deve receber.

Para chamarmos a função criada anteriormente, fazemos simplesmente:
hello();

Prontinho. O C++ vai lá buscar essa função e executar o código que tem nela, veja:
Função Olá, mundo em C++
Você pode invocar (chamar) a função 1, 10 ou um milhão de vezes, basta fazer: hello();, sem precisar repetir 1 milhão de vezes o código, basta reutilizar, usando funções.

Exemplo de uso de funções em C++

Vamos criar duas funções agora.
A menu() exibe um menu de opções, sobre que período do dia você está.

Já na boas_vindas(), o usuário vai ter que digitar alguma opção, que será armazenado na variável op, declarada dentro da função.
Depois, ainda dentro desta função fazemos um tratamento para exibir a mensagem corretamente:
#include <iostream>
using namespace std;

void menu()
{
    cout<<"Que período do dia está:\n";
    cout<<"1. Manhã\n";
    cout<<"2. Tarde\n";
    cout<<"3. Noite\n";
}

void boas_vindas()
{
    int op;
    cin>>op;

    if(op==1)
        cout<<"Bom dia!\n";
    else if(op==2)
        cout<<"Boa tarde!\n";
    else if(op==3)
        cout<<"Boa noite!\n";
    else
        cout<<"Entrada inválida\n";
}

int main()
{
    menu();
    boas_vindas();
    cout<<"Encerrando...\n";

    return 0;
}
Note que tem três funções no código:
  1. menu()
  2. boas_vindas()
  3. main()
A main() é uma função especial do C++, ela é automaticamente executada quando compilamos e executamos nossos códigos. Dentro dela, chamamos primeiro a menu() e somente quando essa terminar de executar, chama a boas_vindas().

Note que somente após o usuário inserir o valor na boas_vindas() e ela te cumprimentar, é que ela vai terminar e vai voltar pra main(), que exibe um cout final de encerramento.

Quando usar uma função

Sempre. O máximo que puder.

Até o momento, em nosso curso, fizemos exemplos pequenos e simples de código.
Mas o normal, quando você se tornar um programador profissional, é fazer sistemas com centenas ou milhares de linhas de código, e é aí que você vai entender o quão importante é o conceito de funções, em C++.

Você deve adquirir o hábito de criar funções pequenas, simples e de fácil entendimento e execução, pois sempre que iniciar um novo projeto, vai usar suas funções antigas e funções já existentes por padrão, do C++.

Essa técnica é chamada de dividir para conquistar, e no decorrer do nosso curso de C++ você vai ver que um programa grande e complexo nada mais é que um monte de programas pequenos e simples, conectados de maneira correta, funcionando em harmonia.

Números primos em C++ - Como descobrir

Neste tutorial, vamos destrinchar os primos. Vamos aprender como verificar se um número é primo ou não, bem como exibir uma lista de quantos primos quisermos, usando laços e loopings, em C++.

Números Primos na Matemática

Um número é dito ser primo quando pode ser dividido somente por 1 e por ele mesmo.
O 7 é primo, você pode dividir só por 1 e por 7, por qualquer outro valor vai dar um resultado quebrado.

O 12 não é primo, pois pode ser dividido por 1, 2, 3, 4, 6 e 12.

Vejamos alguns números primos: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997...

Os primos são uma classe muuuuito especial na Matemática, tendo utilidade em diversos ramos e áreas, como na criptografia.

Vale a pena pesquisar sobre eles, há todo um véu de mistério neles, pois tentam há milênios encontrar uma fórmula para gerar números primos e nada até hoje deu certo.

Será que um dia você consegue? Quem sabe...se ganhar o prêmio Nobel, não esquece de compartilhar a grana com a gente...

Simbora caçar uns primos?

Como Descobrir se um número é primo

Para verificar se um número num é primo, basta verificar seus divisores, de 1 até num.

Por exemplo, vamos testar se o 9 é primo. Basta analisar o resto da divisão por 1, 2, 3, 4, 5, 6, 7, 8, e 9.
Se for primo, somente vai ser divisível por 1 e por ele mesmo, logo vai ter 2 divisores. Mas o resto da divisão vai dar 0 quando fizermos 9%3, logo 3 também é divisor, totalizando 3 divisores, logo não é primo.

Agora o 11.
Podemos pegar o resto da divisão por 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 e 11, que só vai dar 0 pra 1 e pra 11.
Logo, ele é primo.

Ou seja, basta fazer o resto da divisão de num por 1, 2, 3, 4, 5, ..., até num, e contar na variável div (inicializada com 0), quantos divisores tem.

Se for 2, é primo.
Se for mais que 2, não é primo.

Veja o código:
#include <iostream>
using namespace std;

int main()
{
    int aux, num=479001599, div=0;

    for(aux=1 ; aux<=num ; aux++)
        if(num%aux==0)
            div++;

    if(div==2)
        cout<<"É primo"<<endl;
    else
        cout<<"Não é primo"<<endl;
    return 0;
}
Testamos com um número primo gigante, o 479001599.
Aqui levou 1.831s pra verificar, e na sua máquina?

Otimizando a busca por primos

Ora, todo número é divisível por 1.
Então não precisamos fazer o resto da divisão por 1, já é uma checagem a menos.

E também não precisamos testar até num.
Passou da metade, não vai ter mais nenhum divisor possível.

Dando uma enxugada no código, ele fica assim:
#include <iostream>
using namespace std;

int main()
{
    int aux, num=479001599, div=0;

    for(aux=2 ; aux<=num/2 ; aux++)
        if(num%aux==0)
            div++;

    if(div==0)
        cout<<"É primo"<<endl;
    else
        cout<<"Não é primo"<<endl;
    return 0;
}
Agora levou só 1.012s
E na sua máquina?

Podemos ir mais além e calcular até a raiz quadrada de num, ao invés de apenas até num/2 (pesquise o motivo disso):
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int aux, num=479001599, div=0;

    for(aux=2 ; aux<=sqrt(num) ; aux++)
        if(num%aux==0)
            div++;

    if(div==0)
        cout<<"É primo"<<endl;
    else
        cout<<"Não é primo"<<endl;
    return 0;
}
0.004s ! Carai, maluco!

Achando primos num intervalo

Agora vamos imprimir todos os primos num determinado intervalo, de 1 até um valor Máximo, como 100.

Primeiro, uma variável pra testar todos os números de 2 até Max, é a aux.

Para cada número, vamos contar todos os divisores e armazenar na variável div, por isso ela deve começar zerada dentro do primeiro laço.

No segundo FOR, vamos verificar cada número aux, fazendo o resto da divisão deles por 2 até raiz quadrada do número, para verificar se tem divisores.

Se tiver, cai no IF (IF dentro de um FOR que está dentro de outro FOR, que loucura!), que incrementa div.

Após toda essa verificação interna, ele é primo se div tiver 0 como valor, se tiver, então imprimimos o valor de aux, pois é um primo.

Veja como fica o código:
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int aux, coun, Max=100, div;

    for(aux=2 ; aux<=Max ; aux++){
        div=0;

        for(coun=2 ; coun<=sqrt(aux) ; coun++)
            if(aux%coun==0)
                div++;

        if(!div)
            cout<<aux<<" ";
    }

    cout<<endl;

    return 0;
}
Teste com mil, 10 mil, 1 milhão...só agora você tem real noção do poder e capacidade de calcular que tem sua máquina

As instruções BREAK e CONTINUE do C++

Neste tutorial, vamos aprender duas instruções, ou comandos, muito importantes: o break e o continue, em C++.

Instrução BREAK em C++

Se você fez direitinho e na ordem, o curso C++ Progressivo, já deve conhecer este comando break, pois usamos no tutorial:
Switch, case e break

Lá, quando esse comando era executado, ele simplesmente encerrava o teste condicional SWITCH.
Aqui, ele faz a mesma coisa, mas no caso ele serve para interromper um laço, a qualquer instante.

No código abaixo, o C++ fica pedindo um número ao usuário e calculando seu quadrado.
Se em algum momento o usuário digitar 0, o IF se torna verdadeiro e o comando break é acionado, interrompendo sumariamente o laço WHILE:
#include <iostream>
using namespace std;

int main()
{
    int num;

    while(true){
        cout<<"Numero: ";
        cin >>num;

        if(num==0)
            break;

        cout<<num*num<<endl;
    }

    return 0;
}
Ou seja, quando queremos, em algum momento, interromper um laço, usamos a instrução BREAK, que geralmente vem dentro de um teste condicional, dentro de algum looping.

Se tivermos um laço dentro de outro, e dentro deste estiver uma instrução BREAK, somente esse laço mais interno que será interrompido, ok?

O seguinte código fica pedindo notas para o usuário, para calcular a média.
Caso o usuário digite uma nota que não é válida (abaixo de 0 ou acima de 10), o laço WHILE é encerrado e fornecemos a média dos números digitados dessa nota inválida:

#include <iostream>
using namespace std;

int main()
{
    int aux=0;
    float num, sum=0;

    while(true){
        cout<<"Nota: ";
        cin >> num;

        if(num<0 || num>10)
            break;

        sum+=num;
        aux++;
    }

    cout<<"Média: "<<(sum/aux)<<endl;
    return 0;
}
Note que garantimos que os números fornecidos sejam corretos (entre 0 e 10), pois caso contrário o laço é encerrado.

O comando CONTINUE em C++

Se o BREAK encerra o teste condicional ou estrutura de controle, o comando CONTINUE encerra apenas a iteração.

Ou seja, pula pra próxima iteração.

Vamos somar todos os números de 1 até 100, exceto os múltiplos de 4:
#include <iostream>
using namespace std;

int main()
{
    int num, sum=0;

    for(num=1; num<=10 ; num++){
        if(num%4==0)
            continue;
        sum += num;
    }

    cout<<"Total: "<<sum<<endl;
    return 0;
}
Dentro do laço verificamos se o número é divisível por 4, se for, essa iteração é pulada, não rodando o código seguinte ao CONTINUE, vai pra próxima iteração normalmente.

Assim como o BREAK, o comando CONTINUE geralmente ocorre sob determinado teste condicional, quando você quer excluir uma iteração específica do looping.

Vamos refazer o código que calcula a média.
Agora, ao invés de parar a execução, ele pula a iteração, não somando aquela nota inválida na soma:
#include <iostream>
using namespace std;

int main()
{
    int aux=0;
    float num, sum=0;

    while(true){
        cout<<"Nota: ";
        cin >> num;

        if(num>10){
            cout<<"Nota acima de 10 são inválidas"<<endl;
            continue;
        }
        if(num<0){
            cout<<"Nota negativa, encerrando cálculos e exibindo a média: ";
            break;
        }

        sum+=num;
        aux++;
    }

    cout<<(sum/aux)<<endl;
    return 0;
}
Note que a média é calculada apenas para números válidos. Para encerrar o looping, você precisa digitar um valor negativo.

Mega-Sena com C++

Neste tutorial de C++, vamos aprender como contar todas os possíveis palpites da Mega-Sena, bem como vamos ver como exibir todos esses números, usando a técnica de estruturas de repetição aninhadas.

A loteria da Mega-Sena

Muito provavelmente você já jogou na Mega Sena, não é?

Ela funciona assim: você deve escolher 6 dezenas (sena), de um universo de 60 números, de 1 até 60.

No sorteio, tem um globo com 60 bolas e as moças bonitas lá vão tirando bolinha por bolinha...então, obviamente, as dezenas não se repetem, concorda?

No final, eles exibem o resultado na ordem crescente dos valores, ou seja, da dezena menor pra maior.

O 'menor' palpite é:
1 2 3 4 5 6

Já o 'maior' palpite é:
55 56 57 58 59 60

Aqui vem o segredo:

  1. A primeira dezena vai de 1 até 55
  2. A segunda dezena vai de 2 até 56
  3. A terceira dezena vai de 3 até 57
  4. A quarta dezena vai de 4 até 58
  5. A quinta dezena vai de 5 até 59
  6. A sexta dezena vai de 6 até 60

Quantos palpites são possíveis na Mega Sena

Então, vamos lá.
Vamos usar 6 variáveis para as dezenas: dez1, dez2, dez3, dez4, dez5 e a dez6.

A variável acumuladora, para contar quantas iterações (consequentemente, quantos palpites são possíveis na Mega Sena), é a sum.

Agora basta fazer FOR aninhado com FOR e contar quantas possibilidades existem, sempre tendo cuidado com o intervalo que cada dezena pode assumir.

Outro segredo, importante, é que a variável dez1 começa do 1, e as seguintes começam a partir da dezena anterior somado de 1, pois as dezenas são maiores que as outras, já que estamos assumindo que estejam em ordem crescente.

O código:

#include <iostream>
using namespace std;

int main()
{
    int dez1, dez2, dez3, dez4,
        dez5, dez6, sum=0;

    for(dez1=1; dez1<=55 ; dez1++)
        for(dez2=dez1+1; dez2<=56 ; dez2++)
            for(dez3=dez2+1; dez3<=57 ; dez3++)
                for(dez4=dez3+1; dez4<=58 ; dez4++)
                    for(dez5=dez4+1; dez5<=59 ; dez5++)
                        for(dez6=dez5+1; dez6<=60 ; dez6++)
                            sum++;
    cout << "Total : " << sum << endl;

    return 0;
}

E o resultado é:
Contar e exibir todos os palpites da Mega-Sena

Se ainda se lembrar das aulas de análise combinatória, basta calcular (60 seis a seis).
Aqui levou 0.167s pra rodar mais de 50 milhões de iterações, e aí na sua máquina?

Exibindo todos os palpites da Mega-Sena

Agora vamos imprimir na tela todos os possíveis resultados:

#include <iostream>
using namespace std;

int main()
{
    int dez1, dez2, dez3, dez4,
        dez5, dez6;

    for(dez1=1; dez1<=55 ; dez1++)
        for(dez2=dez1+1; dez2<=56 ; dez2++)
            for(dez3=dez2+1; dez3<=57 ; dez3++)
                for(dez4=dez3+1; dez4<=58 ; dez4++)
                    for(dez5=dez4+1; dez5<=59 ; dez5++)
                        for(dez6=dez5+1; dez6<=60 ; dez6++)
                            cout<<dez1<<"-"<<dez2<<"-"<<dez3<<"-"
                                <<dez4<<"-"<<dez5<<"-"<<dez6<<endl;

    return 0;
}

Note que agora é beeeem mais demorado, e isso se deve ao fato da função cout ser mais lenta, demora pra exibir as coisas na sua tela, se a máquina ficasse só fazendo os cálculos, como no exemplo anterior, seria bem mais rápido. Mas aqui temos que mostrar os resultados das iterações, então a coisa é mais morosa mesmo.

Laços aninhados em C++ - Laço dentro de laço

Agora que já treinamos bastante o conceito de laços e loopings, aprendendo a fazer, vamos aprender outro conceito importante, o de laços aninhados, ou laços dentro de laços.

Estruturas de Repetição aninhadas em C++

Veja nos tutoriais anteriores, onde usamos exercícios famosos para fixar nossos conhecimentos em estruturas de repetição, especificamente, nos códigos do laço DO WHILE:

Colocamos um laço FOR dentro do laço DO WHILE.
Ou seja, existe um looping maior, um laço pai, o DO WHILE, que vai ficar repetindo uma estrutura base.

Dentro de cada iteração dessa, um laço FOR é executado.
Esse laço de dentro está aninhado ao laço de fora.

Consegue ver e entender sua função, por que ele funciona?
É bem simples, mas é uma técnica muito poderosa.

Usando laços aninhados em C++

Vamos usar a técnica das estruturas de repetição aninhadas para imprimir um tabuleiro N x N, ou seja, de N linhas e N colunas. Veja um exemplo de tabuleiro 3x3, pra jogar jogo da velha:
-   -   -
-   -   -
-   -   -

O segredo aqui é usar um laço pras linhas e outro, interno ao primeiro, para cuidar das colunas em cada linha.

O primeiro FOR vai de 1 até N, é o responsável pelas linhas.
Note que ao final dele tem uma quebra de linha, para imprimir a próxima iteração na linha de baixo.

Dentro do FOR de linha, vamos imprimir N tracinhos.

Veja como fica nosso código:
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    int lin, col, N;

    cout<<"Tamanho do tabuleiro N x N: ";
    cin >> N;

    for(lin=1 ; lin<=N ; lin++){
        for(col=1 ; col<=N ; col++)
            cout<<" - ";

        cout <<endl;
    }

    return 0;
}

Como usar laços aninhados em C++

Vamos criar um programa para imprimir a seguinte tabela da imagem:

Estruturas de repetição aninhadas

Veja que tabela bonita, que tabela formosa, que tabela bem feita.
Vamos aprender como fazer ela?

Primeiro, note duas duas, ela tem:

  • 4 linhas
  • 4 colunas

Vamos usar dois laços, um para cuidar das linhas e outro para cuidar das colunas.
Para controlar esses laços, vamos usar as variáveis lin e col, bem como uma variável que vai receber os números de 1 até 16, a num.

Vamos, de início, trabalhar nas linhas:
    for(lin=1 ; lin<=4 ; lin++){
        // alguma coisa
        cout <<endl;
    }

Note que ao término de cada iteração, temos que dar uma quebra de linha, para ir para a linha de baixo.

Dentro de cada iteração desta, precisamos imprimir as colunas, que são 4 por linhas.
Então vamos usar outro laço aninhado:
    for(lin=1 ; lin<=4 ; lin++){
        for(col=1 ; col<=4 ; col++){
            // alguma coisa
        }
        cout <<endl;
    }

Dentro desse for aninhado, tamos imprimir os números.
Como a variável col vai de 1 até 4, ele imprime quatro números em cada linha.

Vamos usar a variável num, inicialmente com valor 1, para imprimir esses valores.
Após a iteração interna, temos que incrementar essa variável.

Para a tabela sair bonitinha e formatada, vamos usar o comando setw, para definir como tamanho de 4 espaçamentos (você precisa incluir a biblioteca iomanip, pra usar esse comando).

Veja como ficou nosso código:
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    int lin, col, num=1;

    for(lin=1 ; lin<=4 ; lin++){
        for(col=1 ; col<=4 ; col++){
            cout<<setw(4) << num;
            num++;
        }
        cout <<endl;
    }

    return 0;
}
Bacana, né?

Exemplo de uso de laços aninhados

Vamos agora imprimir um triângulo de asteriscos, do tamanho que o usuário quiser.
Por exemplo, um triângulo de tamanho 5:
*
**
***
****
*****

Note que vai ter 5 linhas.
Na primeira linha, tem 1 coluna.
Na segunda linha, tem 2 colunas.
...
Na quinta coluna, tem 5 colunas.

O primeiro FOR, a variável de controle lin vai de 1 até N, onde N é o tamanho do triângulo que o usuário quiser.
Dentro de cada FOR, vamos usar outro FOR para imprimir os asteriscos. Eles devem imprimir de 1
até lin, consegue captar essa ideia?

Na primeira linha, imprime 1 asterisco.
Na segunda linha, imprime 2 asteriscos.
...
Na N-ésima linha, imprime N asteriscos.

Veja como fica nosso código:
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    int lin, col, N;

    cout<<"Tamanho do triângulo: ";
    cin >> N;

    for(lin=1 ; lin<=N ; lin++){
        for(col=1 ; col<=lin ; col++)
            cout<<"*";

        cout <<endl;
    }

    return 0;
}
Note que o FOR de fora, usa chaves, pois tem mais de uma linha de comando abaixo dele.
Já o FOR de dentro, não precisa, pois ele só tem uma linha de comando.
Cuidado para não confundir as chaves! Faça sempre um espaçamento e uma indentação correta, para não errar.

Laço dentro de laço de laço dentro de laço...

Ok, já vimos como aninhar estruturas de repetição, colocamos um FOR dentro de outro.
E que tal agora colocar mais um FOR, aninhado aos outros dois?

Vamos mostrar todos os horários possíveis de um relógio, durante o dia, no formato:
hour:min:sec

Ou seja, vai de : 00:00:00
Até o : 23:59:59

Vamos usar três variáveis: h, m e s
h vai de 0 até 23, tanto m como s vão de 0 até 59, pois representam os minutos e segundos.

Nosso código fica assim:
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    cout.fill('0');
    for(int h=0 ; h < 24 ; h++)
        for(int m=0 ; m < 60 ; m++)
            for(int s=0; s<60 ; s++){
                cout<<setw(2)<<h<<":";
                cout<<setw(2)<<m<<":";
                cout<<setw(2)<<s<<endl;
            }

    return 0;
}
Usamos o setw(2) para definir 2 caracteres de espaçamento.
Quando não tiver nada pra aparecer nesse espaçamento, vai aparecer 0, pois usamos cout.fill('0')