Módulo 01

PROGRAMAÇÃO COM C++ #

Neste curso aprederemos a programar utilizando uma linguagem de programação bem robusta, de alto desempenho, chamada C++.

C++ é uma linguagem de programação de propósito geral que surgiu como uma extensão da linguagem C, adicionando novos recursos, mas mantendo a compatibilidade com o código já existente em C.

É uma linguagem multiparadigma, o que significa que permite que o código seja escrito de acordo com diferentes paradigmas de programação, ou seja, “estilos” de como o código é organizado e estruturado. Neste primeiro módulo, focaremos no paradigma procedural (como em C), e no próximo módulo explicarei o paradigma orientado a objetos.

Vamos começar!

Criando arquivos de implementação C++ #

Arquivos de implementação em C++ usam a extensão .cpp. Eles contém o código-fonte com a lógica do programa. Por exemplo:

  • aula01.cpp

Para que o computador possa entender e executar esse arquivo, ele deve ser compilado utilizando-se um compilador da linguagem C++. Nesse processo, o seu código-fonte em C++ será transformado em uma linguagem de máquina, que o computador realmente entende. Estudaremos os compiladores em módulos seguintes, neste módulo focaremos apenas na lógica de programação.

IMPORTANTE: O nome do arquivo não deve ter espaços (use sublinhado ou letras juntas, para compor nomes). Por exemplo:

  • primeiro_programa.cpp
  • primeiroPrograma.cpp
  • aplicacaoFuncional_01.cpp

Os compiladores de C++ não impõem muitas restrições quanto ao nome do arquivo, mas existem convenções adotadas como boas práticas de programação. Além disso, os sistemas operacionais normalmente possuem regras de nomeação de arquivos que limitam o uso de alguns caracteres. Dessa forma, além do espaço, também evite a inclusão de caracteres especiais, acentos e cedilhas no nome do arquivo.

Estrutura básica #

A estrutura mínima e mandatória de um código em C++ é:

int main() { }

Todo o programa começa a executar dentro da função main(). É dentro dessas chaves que escrevemos as instruções que o computador deve seguir. Embora programas maiores incluam outras funções, bibliotecas e arquivos separados, a função main é sempre o ponto de partida obrigatório.

O int antes de main indica que a função retorna ao sistema operacional um número inteiro, normalmente usado para sinalizar se o programa terminou com sucesso ou ocorreu algum erro.

Esse código sozinho não faz nada visível. Vamos incrementa-lo para que exiba na tela uma mensagem de boas vindas:

#include <iostream>

int main() { 
    std::cout << "Bem vindo!";

    return 0;
}

Ao ser executado, exibirá a mensagem:

Bem vindo!

Vamos entender:

  • #include < iostream > inclui ao seu arquivo a biblioteca padrão de C++ presente no compilador, permitindo o uso de recursos prontos de entrada e saída de dados, como leitura do teclado e exibição de informações na tela.
    • Em programação, uma biblioteca é um conjunto de códigos prontos criados para facilitar o desenvolvimento de programas. Funcionam como extensões da linguagem, oferecendo recursos adicionais que podem ser reaproveitados no criação de novos programas.
  • std::cout é o recurso da biblioteca padrão iostream utilizado para exibir mensagens na tela.
  • « é o operador que envia o que vem à direita para o cout à esquerda.
  • “Bem vindo!” é a nossa mensagem. Você pode alterar a mensagem, mas ela sempre deverá estar entre as aspas.
  • ; Ponto e vírgula ao final da linha. As linhas de instrução são finalizadas com um ponto e vírgula, para sinalizar ao compilador o final da linha.
  • return 0 retorna um código de saída com o valor zero para o sistema operacional, indicando que o programa terminou com sucesso.

Exemplo com saída de dados #

Vejamos um exemplo com múltiplas saídas:

#include <iostream>

int main() { 
   std::cout << "Iniciando a execução do programa." << std::endl;
   std::cout << "Bem vindo ao curso de C++. " << std::endl;
   std::cout << "Programar é divertido!";

   return 0;
}

A saída será:

Iniciando a execução do programa.
Bem vindo ao curso de C++.
Programar é divertido!

Observe o std::endl adicionado ao final da linha com o operador «.

  • O operador « funciona como um “encadeador de saída”: cada vez que ele é usado, adiciona mais um elemento ao que será mostrado.

  • O símbolo endl indica quebra de linha, como o Enter do teclado. Precisamos adicionar a quebra de linha quando queremos que a próxima mensagem a ser impressa na tela apareça em uma nova linha. Sem o std::endl, a saída seria:

     Iniciando a execução do programa.Bem vindo ao curso de C++.Programar é divertido!
    

Exemplo com entrada de dados #

Com o código a seguir, aprenderemos a introduzir dados ao programa utilizando o teclado:

#include <iostream>

int main()
{
    std::string aluno;
    std::cout << "Digite o seu nome:";
    std::cin >> aluno;
    
    std::cout << "Bem vindo, " << aluno;
    

    return 0;
}

Ao executar, o programa imprimirá apenas a mensagem “Digite o seu nome:”, e ficará aguardando o usuário digitar alguma informação e finalizar com a tecla Enter do teclado. Se o usuário inserir, por exemplo, “Maria”, a saída será:

Digite o seu nome:
Bem vindo, Maria

Vamos entender como esse código funciona:

  • Primeiro, precisamos reservar um espaço de memória do computador para armazenar o que será digitado no teclado. Chamamos esse espaço de variável. Fazemos isso com a instrução:

    std::string aluno;
    
    • string é o tipo da variável. O tipo define qual o tamanho do espaço que será armazenado na memória.
    • aluno é a identificação da variável. Um nome que você pode escolher e que será utilizado sempre que precisar acessar o dado que ficou armazenado.

    Ou seja, com essa instrução, criamos uma variável chamada aluno do tipo string. Estudaremos com detalhes as variáveis e seus tipos na sequencia do curso.

  • Em seguida, imprimimos uma mensagem na tela com std::cout como já aprendemos anteriormente. Esse código não recebe nenhuma informação de entrada.

  • Na sequencia, temos o codigo responsável pela entrada de dados:

    std::cin >> aluno;
    
    • std::cin é o recurso da biblioteca padrão iostream utilizado para receber dados digitados pelo usuário no teclado. Por padrão, ele lê os caracteres até encontrar um espaço ou tabulação, ou uma quebra de linha (Enter).
    • O operador » pega os dados e envia para a variável aluno à direita.
  • Para finalizar, imprimimos na tela uma mensagem persolizada com a instrução:

    std::cout << "Bem vindo, " << aluno;
    

    Perceba que utilizamos novamente o operador « para concatenar à mensagem “Bem vindo,” o valor armazenado na variável aluno.

    Lembre-se que o operador « é um “encadeador de saída”, e adicionará mais elementos à saída, seja um texto fixo entre aspas ou o valor de uma variável. Dessa forma, é possível montar mensagens personalizadas que combinam palavras e dados fornecidos pelo programa ou pelo usuário. Por exemplo, podemos adicionar uma exclamação ao final da mensagem com o comando:

    std::cout << "Bem vindo, " << aluno << "!!!";
    

    Neste caso, a saída será:

      Bem vindo, Maria!!!
    

Namespace std #

Repare que algumas das intruções que utilizamos até agora possuem a notação std:: como um prefixo. Vimos até agora em:

std::cout
std::cin
std::endl
std::string

O prefixo std:: é uma abreviação da palavra inglesa standard, e é utilizada para indicar que esses recursos pertencem a um “espaço de nomes” da biblioteca padrão do C++ (standard-library namespace). Sem o prefixo std::, o compilador não saberia onde procurar esses recursos.

“Espaço de nomes” (ou namespace) é um recurso da linguagem muito útil para garantir organização e segurança no desenvolvimento de projetos grandes. Ele funciona como uma “etiqueta” que indica de onde o comando está vindo, evitando confusões caso existam nomes iguais em outras partes do programa.

Estudaremos a criação e utilização de namespace em módulos seguintes. Nesse primeiro módulo, utilizaremos a diretiva using namespace std; no início do código para simplificar a escrita e evitar repetição. Com essa diretiva, não é mais necessário escrever o prefixo std:: em cada uso. Vejamos um exemplo:

#include <iostream>

using namespace std;

int main() { 
    cout << "Iniciando a execução do programa." << endl;
    cout << "Bem vindo ao curso de C++. " << endl;
    cout << "Programar é divertido!";

    return 0;
}

Comentários #

As linguagens de programação normalmente permitem que o programador adicione comentários ao código. Comentários são trechos de texto inseridos no código com o objetivo de documentar e explicar a lógica implementada, sem serem executados pelo compilador. Comentários podem até servir para desativar temporariamente alguma parte do código durante o processo de desenvolvimento.

Existem duas sintaxes de comentários em C++: de linha e de bloco.

Comentário de Linha #

Utilizamos // para iniciar uma linha de comentário. Todo o conteúdo após as barras será ignorado pelo compilador. Ex:

#include <iostream>

using namespace std;
// Este é um comentário de linha

int main() { 
    // Este é outro comentário de linha
    cout << "Aprendendo sobre comentários!" << endl;

    return 0;
}

Comentário de Bloco #

Utilizamos /* para iniciar um bloco de comentário e */ para finalizar, independente da linha ao qual se encontra. Todo o conteúdo entre /* e */ será ignorado pelo compilador. Ex:

#include <iostream>

using namespace std;
/*
 Este é um comentário de bloco.
 Comentário de bloco pode conter múltiplas linhas.
*/

int main() { 
    /* Este é outro comentário de bloco.
    Comentários são úteis para documentar o código! */
    cout << "Aprendendo sobre comentários!" << endl;

    return 0;
}

Variáveis e tipos básicos #

Variáveis são espaços de memória reservados pelo programa para armazenar dados que podem ser utilizados e manipulados durante a execução. Uma variável precisa ser declarada com um nome, escolhido pelo programador, e um tipo. O tipo indica que tipo de informação pode ser armazenada, quais operações podem ser realizadas com a variável, e quanto de memória será usada para armazená-la.

Tipos de variáveis em C++ incluem:

Tipo Descrição Exemplos de declaração
int Números inteiros int idade;
int numero_1 = 5;
int x = 5483;
float Números fracionados float nota;
float media = 19.7;
float pi = 3.14159;
double Números fracionados com maior precisão. double medicao;
double volumeOceano = 1.3332e9;
double precoBitcoin = 345678.987654;
bool Valor booleano, como verdadeiro ou falso. bool primeiro_acesso;
bool aprovado = 1;
boll estaAtivo = true;
char Um único caracter char simbolo;
char letra = 'A';
char resposta = 's';
string Sequencia de caracteres string nome;
string curso = "Informática"
string conteudo = "Material de estudos para a curso de informática.";

Notas:

  • bool: Em C++, variáveis do tipo bool possuem o valor numérico 1 para representar verdadeiro e o valor 0 para representar falso. A linguagem permite o uso das palavras true e false no código para facilitar a leitura, mas internamente os valores numéricos equivalentes (1 e 0) é que serão armazenados na memória.
  • char: O valor de uma variável do tipo char deve estar entre aspas simples.
  • string: O valor de uma variável do tipo string deve estar entre aspas duplas.
  • double: é usado para armazenar números reais grandes que ocupam mais espaço na memória que o tipo float. É indicado para cenários em que a precisão dos dados é essencial, como cálculos científicos, financeiros ou de engenharia.

Segue um exemplo de código com declaração de variáveis e seus valores:

#include <iostream>

using namespace std;

int main() { 

    // Variáveis do estudante
    string nome = "Maria";       // nome do estudante
    int idade = 20;            // idade do estudante
    float notaMedia = 9.5;     // nota média do estudante
    char turma = 'B';           // turma do estudante
    bool aprovado = true;      // status de aprovação
    double percentualPresenca = 98.75; // porcentagem de presença do estudante
     

    // Exibindo as informações do estudante
    cout << "Dados do estudante: " << endl;
    cout << " Primeiro Nome: " << nome << endl;
    cout << " Idade: " << idade << endl;
    cout << " Nota Média: " << notaMedia << endl;
    cout << " Turma: " << turma << endl;
    cout << " Aprovado? " << aprovado << endl;  // true será mostrado como 1
    cout << " Percentual de presença: " << percentualPresenca << endl;
    return 0;
}

A saída será:

Dados do estudante: 
 Primeiro Nome: Maria
 Idade: 20
 Nota Média: 8.5
 Turma: B
 Aprovado? 1
 Percentual de presença: 98.75

Nós já aprendemos a ler informações do usuário utilizando o teclado como entrada de dados. Vejamos, então, um exemplo equivalente, no qual o usuário poderá fornecer as informações do aluno:


#include <iostream>

using namespace std;
int main() { 
    
    // Declaração das variáveis sem valores iniciais
    string nome;
    int idade;
    float notaMedia;
    char turma;
    bool aprovado;

    // Solicitando os dados ao usuário
    cout << "Digite o primeiro nome do estudante: ";
    cin >> nome;  
    cout << "Digite a idade: ";
    cin >> idade;
    cout << "Digite a nota média: ";
    cin >> notaMedia;
    cout << "Digite a turma (uma letra): ";
    cin >> turma;
    cout << "O estudante foi aprovado? (1 = sim, 0 = não): ";
    cin >> aprovado;

    // Exibindo os dados coletados
    cout << "Dados do estudante: " << endl;
    cout << "Primeiro Nome: " << nome << endl;
    cout << "Idade: " << idade << endl;
    cout << "Nota Média: " << notaMedia << endl;
    cout << "Turma: " << turma << endl;
    cout << "Aprovado? " << aprovado << endl;
    
     return 0;
}

Operadores #

Operadores são símbolos especiais usados para realizar operações sobre variáveis e valores. Eles permitem executar cálculos, comparar dados e tomar decisões dentro do programa. Os principais grupos de operadores que veremos a seguir são:

  • Operadores aritméticos
  • Operadores relacionais
  • Operadores lógicos

Operadores aritméticos #

Esses operadores são usados para realizar cálculos matemáticos. Eles funcionam com variáveis numéricas, como int e float.

Operador Operação Exemplo de uso
+ Adição resultado = a + b
- Subtração resultado = a - b
* Multiplicação resultado = a * b
/ Divisão resultado = a / b
% Resto da divisão (módulo) resto = a % b
++ Incremento (aumenta o valor da variável em 1) a++ ou ++a
-- Decremento (reduz o valor da variável em 1) b-- ou --b

Os operadores de incremento (++) e decremento (- -) podem ser usados antes ou depois da variável. O modo é chamado de pré-fixado ou pós-fixado:

  • No pré-fixado (++a, --b), a variável é atualizada antes de ser usada na expressão.
  • No pós-fixado (a++, b--), a variável é usada primeiro, e só depois é atualizada, ou seja, na próxima linha de instrução.

Operadores relacionais #

São usados para comparar valores. O resultado dessas comparações é sempre verdadeiro (true) ou falso (false).

Operador Operação Exemplo de uso
== Igual a resultado = (a == b)
!= Diferente de resultado = (a != b)
> Maior que resultado = (a > b)
< Menor que resultado = (a < b)
>= Maior ou igual a resultado = (a >= b)
<= Menor ou igual a resultado = (a <= b)

Operadores lógicos #

São utilizados para combinar expressões lógicas (condições). O resultado também é sempre true ou false.

Operador Operação Exemplo de uso
&& E lógico
(verdadeiro se ambas as condições forem verdadeiras)
resultado = (a > b && b < c)
|| OU lógico
(verdadeiro se pelo menos uma condição for verdadeira)
resultado = (a > b || b < c)
! NÃO lógico
(inverte o valor lógico da expressão)
resultado = !(a > b)

Exemplo de uso #

Segue exemplo mais completo de utilização dos operadores:


#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 3, c = 5;

    // Operadores aritméticos
    cout << "Soma: " << a + b << endl;
    cout << "Subtração: " << a - b << endl;
    cout << "Multiplicação: " << a * b << endl;
    cout << "Divisão: " << a / b << endl;
    cout << "Resto: " << a % b << endl;

    // Operadores relacionais
    cout << "a é igual a b? " << (a == b) << endl;
    cout << "a é maior que b? " << (a > b) << endl;

    // Operadores lógicos
    cout << "a > 5 e b < 5? " << (a > 5 && b < 5) << endl;
    cout << "a > 5 ou b > 5? " << (a > 5 || b > 5) << endl;
    cout << "a não é menor que b? " << !(a < b) << endl;

    //Operadores unários de incremento e decremento
    cout << "Incremento pré-fixado: " << ++c << endl; // imprime 6
    c = 5;
    cout << "Incremento pós-fixado: " << c++ << endl; // imprime 5, mas depois 'c' passa a valer 6


    return 0;
}

A saída esperada é:

Soma: 13
Subtração: 7
Multiplicação: 30
Divisão: 3
Resto: 1
a é igual a b? 0
a é maior que b? 1
a > 5 e b < 5? 1
a > 5 ou b > 5? 1
a não é menor que b? 1
Incremento pré-fixado: 6
Incremento pré-fixado: 5

Na saída dos exemplos com operadores lógicos e/ou relacionais, lembre-se que 1 significa verdadeiro e 0 significa falso.

Estrutura condicional: if else #

Utilizamos estruturas condicionais para permitir que o programa tome decisões sobre qual parte do código será executado com base em alguma condição. A forma geral da estruutra é:

if (condição) {
    // bloco de código executado se a condição for verdadeira
} else {
    // bloco de código executado se a condição for falsa
}

A estrutura if (do inglês, “se”) é usada para executar um bloco de código apenas se uma condição for verdadeira. A estrutura else (do inglês, “senão”) é opcional, e permite definir um bloco alternativo de instruções, que será executado caso a condição seja falsa.

A condição é uma expressão que deve resutlar em um valor booleano (verdadeiro ou falso). Para isso, utilizamos operadores relacionais (como ==, >, <, !=) e lógicos (como &&, ||, !), conforme já estudado.

Exemplo:

#include <iostream>
using namespace std;

int main() {
    float nota;

    cout << "Digite a nota do aluno: ";
    cin >> nota;

    if (nota >= 7.0) {
        cout << "Aluno aprovado!";
    } else {
        cout << "Aluno reprovado!";
    }

    return 0;
}

Estruturas condicionais também podem ser aninhadas, permitindo testar condições em sequência. Por exemplo:

#include <iostream>
using namespace std;

int main() {
    float temperatura;

    cout << "Digite a temperatura em graus Celsius: ";
    cin >> temperatura;

    if (temperatura >= 35.0) {
        cout << "Clima quente!";
    } else if (temperatura >= 25.0) {
        cout << "Clima agradável.";
    } else if (temperatura >= 15.0) {
        cout << "Clima ameno.";
    } else {
        cout << "Clima frio.";
    }

    return 0;
}

Vejamos mais um exemplo, no qual a comparação da estrutura condicional é feita com variável do tipo string:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string turno;

    cout << "Digite o turno em que você estuda (manha, tarde ou noite): ";
    cin >> turno;

    if (turno == "manha") {
        cout << "Bom dia!";
    } else if (turno == "tarde") {
        cout << "Boa tarde!";
    } else if (turno == "noite") {
        cout << "Boa noite!";
    } else {
        cout << "Turno inválido. Verifique o valor digitado.";
    }

    return 0;
}

Estrutura de repetição: for #

A estrutura de repetição (ou laço) for permite que um bloco de código seja executado várias vezes, enquanto uma condição específica for verdadeira. A sintaxe geral é:

for (inicialização; condição; incremento) {
    // bloco de código que será repetido
}

No qual:

  • inicialização: define e inicializa uma variável de controle do laço de repetição. Ex. ``ìnt i = 0```.
  • condição: é uma expressão lógica que é verificada antes de cada repetição. Enquanto for verdadeira, o bloco será executado. Ex. i < 5.
  • incremento/decremento: atualiza a variável de controle a cada repetição. Ex. i++.

Com essas três etapas, o comando for repete o bloco de código delimitado por { } enquanto a condição permanecer verdadeira. Normalente, a mudança de estado dessa condição - de verdadeiro pra falso - ocorre graças à atualização da variável de controle, feita por meio de um incremento ou decremento a cada repetição.

Exemplo:

#include <iostream>
using namespace std;

int main() {
    for (int i = 1; i <= 5; i++) {
        cout << "Número: " << i << endl;
    }
    return 0;
}

A saída será:

Número: 1
Número: 2
Número: 3
Número: 4
Número: 5

Vejamos um exemplo semelhante, mas com decremento da variável de controle:

#include <iostream>
using namespace std;

int main() {
    for (int i = 5; i >= 1; i--) {
        cout << "Número: " << i << endl;
    }
    return 0;
}

A saída será:

Número: 5
Número: 4
Número: 3
Número: 2
Número: 1

Segue mais um exemplo, agora, com leitura de dados dentro da estrutura de repetição. No exemplo, o algoritmo lê o valor de uma nota a cada repetição, e calcula incrementalmente a média das notas:

#include <iostream>
using namespace std;

int main() {
    float nota, soma = 0;
    int quantidade = 5;

    for (int i = 1; i <= quantidade; i++) {
        cout << "Digite a nota " << i << ": ";
        cin >> nota;
        soma += nota; // soma = soma + nota
    }

    float media = soma / quantidade;
    cout << "A média das notas é: " << media << endl;

    return 0;
}

Um exemplo de saída é:

Digite a nota 1: 8
Digite a nota 2: 7
Digite a nota 3: 9
Digite a nota 4: 6
Digite a nota 5: 8
A média das notas é: 7.6

Estrutura de repetição: while #

A estutura while, semelhante à estrutura for, também é utilizada para repetir um bloco de código enquanto uma condição for verdadeira. A sintaxe geral é:

while (condição){
    //bloco de código que será repetido

}

Perceba que a estrutura do while não inclui, em sua própria sintaxe, a inicialização nem o incremento da variável de controle, como vimos no for. Por isso, esses comandos precisam ser escritos separadamente no código: a inicialização antes do início do laço, e o incremento dentro do bloco de repetição.

Vejamos um exemplo:

#include <iostream>
using namespace std;

int main() {
    int i = 1; // Inicializa a variável de controle

    while (i <= 5) {
        cout << "Número: " << i << endl;
        i++; // Incrementa a variável de controle
    }

    return 0;
}

A saída será:

Número: 1
Número: 2
Número: 3
Número: 4
Número: 5

Segue uma versão do algoritmo para cálculo de média de notas informadas pelo usuário (visto na seção da estrutura for), utilizando a estrutura while:

#include <iostream>
using namespace std;

int main() {
    float nota, soma = 0;
    int quantidade = 5;
    int i = 0;

    while (i <= quantidade) {
        cout << "Digite a nota " << i << ": ";
        cin >> nota;
        soma += nota; // soma = soma + nota
        i++;
    }

    float media = soma / quantidade;
    cout << "A média das notas é: " << media << endl;

    return 0;
}

Funções #

Em programação, uma função é um bloco de código reutilizável que executa uma tarefa específica. O uso de funções deixa o código mais organizado, pois separa as partes do programa em blocos menores e mais compreensíveis.

Uma função pode, opcionalmente, receber valores de entrada, e também pode retornar um resultado como saída da função. Chamados de parâmetros de entrada e parâmetro de saída.

Vejamos, primeiro, a estrutura básica de uma função sem parâmetros de entrada e de saída:

void nome_da_função() {
    //Bloco de código da função
}

Segue um exemplo de declaração e chamada de uma função:

#include <iostream>
using namespace std;

void mensagemBoasVindas() {
    cout << "Bem-vindo ao curso de C++!" << endl;
}

int main() {
    mensagemBoasVindas(); // chamada da função

    return 0;
}

A saída será:

Bem-vindo ao curso de C++!

Vamos entender:

  • Assim como nome de variáveis, nomes de funções são escolhidos pelo programador, e seguem as mesmas regras de nomeação de variáveis (podem conter letras, números e o caracterer sublinhado (_), devendo começar com uma letra ou sublinhado).
  • O nome da função é mensagemBoasVindas. Ela foi declarada antes do bloco da função main().
  • void indica que a função não terá retorno.
  • Para que a função seja executada, ela precisa ser chamada em algum ponto do código. Nesse exemplo, chamamos a função dentro do bloco main() com a instrução mensagemBoasVindas();.
  • O código começa a ser executado a partir do bloco main(). Nesse exemplo, a primeiro instrução do bloco é a chamada da função. Dessa forma, o fluxo de execução é redirecionado para o bloco de instruções da função. Ao finalizar o bloco da função, o fluxo de execução retorna para a próxima instrução do bloco main().

Vejamos outro exemplo, com declaração de duas funções:

#include <iostream>
using namespace std;

// Primeira função
void primeiraFuncao() {
    cout << "Mensagem da primeira função." << endl;
}

// Segunda função
void segundaFuncao() {
    cout << "Mensagem da segunda função." << endl;
}

int main() {
    cout << "Início do programa no main." << endl;

    primeiraFuncao(); // chama a primeira função

    cout << "De volta ao main, depois da primeira função." << endl;

    segundaFuncao(); // chama a segunda função

    cout << "Final do programa no main." << endl;

    return 0;
}

A saída será:

Início do programa no main.
Mensagem da primeira função.
De volta ao main, depois da primeira função.
Mensagem da segunda função.
Final do programa no main.

Com retorno #

A estrutura básica para declarar uma função com tipo de retorno é:

tipo_de_retorno nome_da_função() {
    //Bloco de código da função

    return valor;
}

O tipo_de_retorno indica o tipo de dado que a função entregará de volta após ser executada. Esse tipo pode ser, por exemplo, int, float, str, string, entre outros. Quando a função não precisa devolver nenhum valor, como vimos na seção anterior, utiliza-se o tipo void. Para retornar um valor ao ponto do programa onde a função foi chamada, utilizamos a instrução return, seguida do valor compatível com o tipo de retorno definido. Exemplo:

#include <iostream>
using namespace std;

// Função que retorna um número inteiro
int somar() {
    int a = 5;
    int b = 3;
    return a + b; // Retorna o resultado da soma
}

int main() {
    int resultado = somar(); // Recebe o valor retornado pela função
    cout << "O resultado da soma é: " << resultado << endl;
    return 0;
}

No exemplo acima, a função somar() realiza uma operação e retorna o valor da soma para o ponto onde foi chamada. O valor é então armazenado na variável resultado dentro do main().

Poderíamos, também, retornar um valor diretamente, ou uma variável, como no exemplo a seguir:

#include <iostream>
using namespace std;

// Função que retorna um número inteiro
int somar() {
    int a = 5;
    int b = 3;
    int soma = a + b
    return soma; // Retorna a variável com o resultado da soma
}

int main() {
    int resultado = somar(); // Recebe o valor retornado pela função
    cout << "O resultado da soma é: " << resultado << endl;
    return 0;
}

Com parâmetros de entrada #

Uma função com parâmetros de entrada não depende apenas de valores fixos dentro dela. Ela trabalha com valores fornecidos pelo programa no momento da chamada, através dos parâmetros de entrada.

A estrutura básica é:

// Com um parâmetro de entrada
tipo_de_retorno nome_da_função(tipo_do_parametro parametro) {
    //Bloco de código da função

    return valor;
}

// Com mais de um parâmetro de entrada:
tipo_de_retorno nome_da_função(tipo1 parametro1, tipo2 parametro2, ...) {
    //Bloco de código da função

    return valor;
}

Lembrando que o retorno da função é opcional e não depende dos parâmetros de entrada. Se não tiver um retorno, utilizamos o void na declaração da função.

Segue um exemplo da função somar(), visto na seção anterior, mas agora com parâmetros de entrada:

#include <iostream>
using namespace std;

// Função que retorna um número inteiro
int somar(int a, int b) {
    return a + b; // Retorna o resultado da soma
}

int main() {
    int valor_1 = 5;
    int valor_2 = 3;
    int resultado = somar(valor_1, valor_2); // Recebe o valor retornado pela função
    cout << "O resultado da soma é: " << resultado << endl;

    return 0;
}

Nesse exemplo, a função somar() recebe dois parâmetros de entrada (a e b), cujos valores são passados na chamada da função através de variáveis que foram declaradas no bloco main(). As variáveis valor_1e valor_2 não fazem parte da função somar() e não podem ser alteradas pela função, apenas os seus valores serão copiados.

Vejamos mais alguns exemplos de chamada de função:

#include <iostream>
using namespace std;

// Função que retorna um número inteiro
int somar(int a, int b) {
    return a + b; // Retorna o resultado da soma
}

int main() {
    int valor_1 = 0;
    int valor_2 = 0;
    int resultado = 0;

    cout << "Digite o valor 1: ";
    cin >> valor_1;
    cout << "Digite o valor 2: ";
    cin >> valor_2; 
    
    resultado = somar(valor_1, valor_2); 
    cout << "O resultado da soma é: " << resultado << endl;

    //Chamada diretamente com valores
    resultado = somar(3, 9);
    cout << "O novo resultado da soma é: " << resultado << endl;

    return 0;
}

Segue mais um exemplo de função:

#include <iostream>
using namespace std;

// Função que recebe duas notas e calcula a média
float calcularMedia(float n1, float n2) {
    float media = (n1 + n2) / 2;

    if (media >= 7.0)
        cout << "Aluno aprovado!" << endl;
    else
        cout << "Aluno reprovado!" << endl;

    return media;
}

int main() {
    float nota1, nota2;
    cout << "Digite as duas notas do aluno: ";
    cin >> nota1 >> nota2;

    float m = calcularMedia(nota1, nota2);
    cout << "A média final foi: " << m << endl;

    return 0;
}

Com múltiplos retornos #

Uma função pode ter mais de um comando return dentro de seu bloco de código. O return não apenas envia um valor de volta ao programa chamador, mas também encerra imediatamente a execução da função, e nada depois dele é executado. Isso significa que a execução da função pode terminar em diferentes momentos, dependendo das condições verificadas.

Exemplo:


#include <iostream>
using namespace std;

// Função que avalia a média e retorna uma mensagem
string verificarSituacao(float media) {
    if (media >= 7.0) {
        return "Aprovado!";
    } 
    else if (media >= 3.0) {
        return "Em recuperação.";
    } 
    else {
        return "Reprovado.";
    }
}

int main() {
    float nota;

    cout << "Digite a média do aluno: ";
    cin >> nota;

    string resultado = verificarSituacao(nota);
    cout << "Situação do aluno: " << resultado << endl;

    return 0;
}

Escopo de variáveis #

O escopo de uma variável define onde ela pode ser acessada dentro do programa. Cada variável “vive” apenas dentro do bloco de código em que ela foi declarada - delimitado por chaves { }.

Existem três tipos principais de escopo onde uma variável pode ser declarada:

  1. No escopo global (fora de qualquer função, inclusive fora de main());
  2. Dentro da função main();
  3. Dentro de uma função comum.

Escopo global #

As variáveis com escopo global são declaradas fora de qualquer função (geralmente no início do programa). Elas podem ser acessadas e modificadas por qualquer função dentro do mesmo arquivo. Exemplo:

#include <iostream>
using namespace std;

int contadorGlobal = 0;  // variável global

void incrementar() {
    contadorGlobal++;    // acessa e altera a variável global
}

int main() {
    cout << "Contador inicial: " << contadorGlobal << endl;
    incrementar();
    cout << "Contador após incremento: " << contadorGlobal << endl;
    return 0;
}

No exemplo, a variável global contadorGlobal foi declarado no inicio do arquivo, fora de qualquer função. A variável pode ser acessada e modificada pela função incrementar() e pela função main().

Dentro da função main() #

Variáveis declaradas dentro da função main()são chamadas de locais. Elas só podem ser usadas dentro desse bloco principal, e outras funções não conseguem acessá-las diretamente. Esse é o tipo de variável que estamos utilizando desde o início desse módulo. Exemplo:

#include <iostream>
using namespace std;

int main() {
    int idade = 20;  // variável local ao main
    cout << "Idade: " << idade << endl;
    return 0;
}

Dentro de uma função comum #

Como vimos na seção anterior de funções, cada função também pode ter suas próprias variáveis locais, que são declaradas dentro do bloco { } da função. Essas variáveis são criadas quando a função é chamada e destruídas quando ela termina sua execução. Elas não podem ser acessadas fora da função. Exemplo:

#include <iostream>
using namespace std;

void mostrarNota() {
    float nota = 8.5;  // variável local da função
    cout << "Nota do aluno: " << nota << endl;
}

int main() {
    mostrarNota();
    // cout << nota; // ERRO: 'nota' não é visível aqui
    return 0;
}

No exemplo acima, a variável nota existe apenas dentro da função mostrarNota(). Ao final da execução dessa função, ela é automaticamente removida da memória. Perceba que essa variável não pode ser acessada diretamente pela função main().

Vetores #

Até agora, quando queríamos armazenar alguma informação dentro do programa — ou seja, guardar dados temporariamente na memória do computador — utilizamos variáveis, e cada variável era capaz de guardar apenas um único valor por vez, como um número, uma letra ou um texto.

Porém, em muitos casos precisamos lidar com vários valores do mesmo tipo ao mesmo tempo: por exemplo, uma lista de notas de alunos, uma coleção de números sorteados, ou uma sequência de nomes cadastrados. Criar dezenas ou centenas de variáveis diferentes para isso seria inviável e confuso.

Surge então a necessidade de uma estrutura de dados que agrupe vários valores sob um mesmo nome, permitindo acessá-los e manipulá-los facilmente. Existem várias estruturas de dados práticas e modernas, e nesse primeiro módulo aprenderemos o vector (vetores).

Em C++, vetores são estruturas utilizadas para armezenar uma sequência de elementos do mesmo tipo, funcionando como uma lista dinâmica capaz de crescer ou diminuir conforme a necessidade do programa.

Antes de usar um vetor, é necessário incluir a biblioteca vector no cabeçalho do arquivo, com a instrução:

#include <vector>

Essa biblioteca faz parte da STL (Standard Template Library) do C++, e foi criada para facilitar o trabalho com listas dinâmicas de elementos. Dentro da biblioteca estão definidos diversos métodos e funcionalidades que permitem, por exemplo, inserir, remover, acessar, buscar, e percorrer elementos em um vetor.

Podemos declarar um vetor vazio, ou já contendo elementos. As sintaxes são:

// Vetor vazio
vector<tipo_do_conteúdo> nome;

// Vetor com N elementos
vector<tipo_do_conteúdo> nome = {valor_1, valor_2, ..., valor_N};

Vejamos um exemplo:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    // Vetor de nomes (strings)
    vector<string> alunos = {"Ana", "João", "José", "Maria"};

    // Vetor de notas (números reais)
    vector<float> notas = {8.5, 7.2, 9.0, 7.8};

    cout << "Lista de alunos e suas notas:" << endl;

    // Exibindo os dois vetores juntos
    for (int i = 0; i < alunos.size(); i++) {
        cout << alunos[i] << " - " << notas[i] << endl;
    }

    return 0;
}

A saída do programa será:

Lista de alunos e suas notas:
Ana - 8.5
João - 7.2
José - 9
Maria - 7.8

Vamos entender:

  • vector<string> alunos = {"Ana", "João", "José", "Maria"}; cria um vetor chamado alunos, que armazena valores do tipo string. O vetor é inicializado com os valores indicados na ordem de declaração, e cada valor é associado a um índice. Os índices começam a contar do zero, e são incrementados em 1 a cada posição no vetor. No exemplo, após essa instrução, teremos o seguinte conteúdo na memória:

    Índice Valor
    0 Ana
    1 João
    2 José
    3 Maria
  • Da mesma forma, vector<float> notas = {8.5, 7.2, 9.0, 7.8}; cria um vetor chamado notas que armazena valores do tipo float. Após essa instrução, teremos esse conteúdo na memória:

    Índice Valor
    0 8.5
    1 7.2
    2 9.0
    3 7.8
  • A estrutura de repetição for está percorrendo os dois vetores ao mesmo tempo, e imprimindo cada par de elementos correspondentes. Isso ocorre pois alunos[i] acessa o conteúdo que está armazenado na posição i do vetor alunos, da mesma forma que notas[i] também acessa o conteúdo que está armazenado na posição i do vetor notas.

  • alunos.size() acessa o método size() da biblioteca vector que retorna o número de elementos presentes no vetor.

Resumo das principais operações #

A tabela abaixo sumariza as principais operações que podemos fazer com vetores:

Operação Descrição
push_back(valor) Insere no final do vetor.
insert(pos, valor) Insere em posição específica.
pop_back() Remove o último elemento do vetor.
erase(pos) Remove em posição específica.
clear() Remove todos os elementos.
empty() Verifica se o vetor está vazio
size() Retorna o tamanho atual.
at(i) / [i] Acessa um elemento.
begin() / end() Retorna iteradores para o início e o fim.

Vejamos exemplos de aplicações por operação nas seções seguintes.

Inserindo no final do vetor #

Utilizamos o comando push_back(valor) para inserir o conteúdo valor no final de um vetor. Exemplo:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<string> cores;

    cores.push_back("branco");
    cores.push_back("azul");
    cores.push_back("verde");

    for(int i = 0; i < cores.size(); i++){
        cout << cores[i] << endl;
    }

    return 0;
}

A saída será

branco
azul
verde

Inserindo no inicio/meio #

Para inserir elementos em posições específicas dentro de um vetor, utilizamos o método insert(posição, valor), no qual o primeiro parâmetro deve ser um iterador que indica o ponto de inserção. Em geral, criamos esse iterador usando o comando:

nome_do_vetor.begin() + número_inteiro

O método begin() retorna um iterador que aponta para o primeiro elemento do vetor, ou seja, a posição 0. A partir dele, podemos deslocar o ponto de inserção somando um número inteiro. Assim:

  • begin() + 1 significa posição 1 do vetor;
  • begin() + 2 significa posição 2 do vetor;
  • … e assim por diante.

Exemplo:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<string> cores = {"branco","azul","verde"};

    cores.insert(cores.begin() + 1, "amarelo");

    for(int i = 0; i < cores.size(); i++){
        cout << cores[i] << endl;
    }

    return 0;
}

A saída será

branco
amarelo
azul
verde

Acessando elementos #

Como vimos no primeiro exemplo de vetores, acessamos os elementos em um vetor com a sintaxe:

nome_do_vetor[numero_posição];

Por exemplo, o trecho de código abaixo imprimiria as cores branco e verde:


vector<string> cores = {"branco", "azul", "verde"};
    
cout << cores[0] << " e " << cores[2];   

Atualizando valores #

Para alterar o valor de um elemento, basta acessar a posição desejada com a sintaxe:

nome_do_vetor[numero_posição] = novo_valor

Exemplo:


vector<string> cores = {"branco", "azul", "verde"};
    
cores[1] = "amarelo";   //Atualização do valor

for(int i = 0; i < cores.size(); i++){
        cout << cores[i] << endl;
}

A saída será:

branco
amarelo
azul

Removendo elementos #

Podemos remover o último elemento com o comando pop_back() ou remover um elemento em posição específica com o comando erase(). As sintaxes são:

//Remove o último elemento
nome_do_vetor.pop_back();

//Remove em posição específica
nome_do_vetor.erase(nome_do_vetor.begin() + número_inteiro);

Vejamos um exemplo:


vector<string> cores = {"rosa", "branco", "azul", "verde"};
    
cores.pop_back(); // remove o verde
cores.erase(cores.begin()); //remove o rosa

for(int i = 0; i < cores.size(); i++){
        cout << cores[i] << endl;
}

A saída será:

branco
azul

Também é possível remover todos os elementos do vetor de uma só vez utilizando o comando clear():


vector<string> cores = {"rosa", "branco", "azul", "verde"};
    
if(cores.empty()){
    cout << "O vetor já está vazio.";    
}else{
    cout << "Apagando todos os elementos do vetor."
    cores.clear();
}

No exemplo acima, utilizamos a função empty(), que verifica se o vetor está vazio. Ela retorna o valor false (0) quando o vetor contém elementos e true (1) quando está vazio. No exemplo, adicionamos uma estrutura condicional para que o comando clear seja executado apenas quando o vetor possuir elementos, evitando uma operação desnecessária.

Entrada de dados com getline() #

A função getline() é utilizada para ler uma linha inteira de texto digitada pelo usuário, incluindo espaços em branco.

Enquanto o cin lê apenas até o primeiro espaço, o getline()captura tudo até o final da linha (até o Enter). A sintaxe de uso é:

getline(cin, nome_variável_string);

  • cin indica que a leitura virá do teclado.
  • variável_string é a variável do tipo string que receberá o texto.

Exemplo:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string nomeCompleto;

    cout << "Digite seu nome completo: ";
    getline(cin, nomeCompleto);

    cout << "Olá, " << nomeCompleto << "! Seja bem-vindo.";
    return 0;
}

Um exemplo de saída é:

Digite seu nome completo: Ana Maria da Silva
Olá, Ana Maria da Silva! Seja bem-vindo.

IMPORTANTE: Cuidado ao usar getline()depois de um cin.

Quando utilizamos o cinpara ler números ou palavras e depois tentamos usar o getline(), pode acontecer um “erro” comum no compilador, no qual o programa pula a leitura da linha. Isso ocorre porque, ao apertar Enter depois do cin, um caractere de nova linha (\n) fica na memória de entrada do teclado. O getline()acaba lendo esse \n e entende que a linha está “vazia”.

Para corrigir esse problema, precisamos limpar a memória antes de usar o getline() com o comando:

cin.ignore()

Vejamos um exemplo:

#include <iostream>
#include <string>
using namespace std;

int main() {
    int idade;
    string nome;

    cout << "Digite sua idade: ";
    cin >> idade;

    cin.ignore(); // limpa o buffer antes do getline

    cout << "Digite seu nome completo: ";
    getline(cin, nome);

    cout << "Olá, " << nome << "! Você tem " << idade << " anos.";
    return 0;
}

(EM DESENVOLVIMENTO)