Resumo da Aula 4

Sumário

Passagem de argumentos por valor e por referência

A passagem de argumentos por valor efectua uma cópia dos valores dos argumentos para os parâmetros respectivos, que são instâncias (variáveis ou constantes) locais à rotina: os parâmetros são construídos e inicializados com o valor dos argumentos.  A declaração de uma função que recebe os seus argumentos por valor tem o seguinte aspecto:

int sucessorDe(int i);

A passagem de argumentos por referência utiliza como parâmetros os próprios argumentos: os parâmetros servem como sinónimos dos argumentos.  A declaração de um procedimento que passa os seus argumentos por referência tem o seguinte aspecto:

void incrementa(int& i);

A invocação de rotinas com passagem de argumentos por valor não altera nunca o valor dos argumentos.  A utilização de rotinas com passagem de argumentos por referência (não constantes) pode alterar o valor dos argumentos.

Evite escrever funções que recebam os seus argumentos por referência!  Uma função deve limitar-se a calcular um valor, sem alterar nenhuma variável que lhe seja externa.

1.1  Exemplo

int sucessorDe(int i)
{
    ++i;
    return i;
    // Seria mais simples e preferível escrever:
    // return i + 1;
}

void incrementa(int& i)
{
    ++i;
}

int a = 1;
int b = sucessorDe(a);

cout << "Sucessor de " << a << " é " << b << '.' << endl;

// A última instrução escreve no ecrã:
//     Sucessor de 1 é 2.

incrementa(a);

cout << "a passou para " << a << '.' << endl;

// A última instrução escreve no ecrã:
//     a passou para 2.

A utilização da passagem por referência levou à alteração do valor da variável a enquanto a passagem por valor não teve qualquer efeito sobre o seu valor.

Variáveis locais e globais

int x;          // a variável global x está disponível dentro da função
                // f() e dentro da função main().
                // Não é aconselhável a utilização de variáveis globais!
                // (A utilização de constantes globais não tem qualquer
                // problema.)
int f(int a)    // o parâmetro a está disponível apenas dentro da função f(),
{               // uma vez que é uma variável local a f().
    int y;      // a variável local y só está disponível dentro da função f().
    ...
}

int main()
{
    int z;      // a variável local z só está disponível dentro da
                // função main().
    ...

    // A um conjunto de instruções dentro de chavetas chama-se uma
    // instrução composta ou bloco de instruções:
    {
        int w;  // a variável local w só está disponível a partir deste ponto, ou
                // seja, desde a sua definição...
                // ...
    }           // ... até este ponto, ou seja, até ao final do bloco de instruções
                // onde foi definida.
}

2.1  Exemplo

#include <iostream>

using namespace std;

double const pi = 3.1416;           // pi: constante global.

/** Devolve o perímetro de uma circunferência com o raio dado.
    @pre 0 <= raio.
    @post perímetro = 2 × pi × raio. */
double perímetroDeCircunferênciaDeRaio(double const raio)
                                    // raio:
parâmetro da função.
{
    double resultado =              // início do âmbito da variável resultado.
        2.0 * pi * raio;
    return resultado;
}                                   // fim do âmbito das variáveis
                                    // raio e resultado.

int main()
{
    cout << "Insira o raio: ";
    double r;                        // início do âmbito da variável r.
    cin >> r;
    cout << "Perímetro : " << perímetroDeCircunferênciaDeRaio(r) << endl;
    cout << "Perímetro : " << 2.0 * pi * r << endl;
}                                   // fim do âmbito da variável r.

O tipo string

A biblioteca padrão do C++ disponibiliza um tipo (na realidade uma classe, como se verá) chamado string que permite manipular cadeias de caracteres representando, por exemplo, texto ou palavras.  As variáveis deste tipo no fundo consistem em sequências de variáveis do tipo char, às quais se acede através de uma indexação, pois cada variável tem um número de ordem na sequência.

Para definir uma variável deste tipo (da classe string) é necessário acrescentar ao topo do programa a linha:

#include <string>

A definição de uma variável deste tipo pode ser feita de várias formas.  Por exemplo:

string c1("Uma cadeia de caracteres qualquer");

string c2; // a cadeia fica vazia!

string c3(10, '-'); // uma cadeia com 10 caracteres '-'.

É possível saber o comprimento de cadeia de caracteres c1 usando a expressão:

c1.length()

Esta expressão é de um tipo aritmético inteiro sem sinal não especificado (i.e., pode ser unsigned short int, unsigned int ou unsigned long int, consoante a implementação).  Por isso, a expressão é do tipo string::size_type, que é sinónimo de um dos três possíveis tipos referidos.

As cadeias de caracteres são indexáveis, tais como as matrizes clássicas e os vectores, que se verão mais tarde. 

Seja a definição

string nome("Manel");

Para atribuir a letra 'g' ao terceiro caractere da cadeia pode-se escrever: nome[2] = 'g'; // atribui o caractere 'g' ao 3º caractere da cadeia. ou int i = 2;
nome[i] = 'g'; // atribui o caractere 'g' ao 3º caractere da cadeia.
Em ambos os casos se usou o chamado operador de indexação, ou seja, [].

Importante:  Os índices de uma cadeia de caracteres começam em zero.  Na cadeia nome acima o índice 0 corresponde ao primeiro caractere da cadeia e o índice 5 não corresponde a nenhum caractere da cadeia!

Formas de identificar caracteres de uma cadeia
Número de ordem do caractere Posição ou índice
0
1
2
3
etc. etc.

3.1  Exemplo

Por exemplo, para percorrer uma cadeia palavra introduzida pelo utilizador e escrever todos os seus caracteres isoladamente no ecrã pode-se usar o seguinte programa:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    cout << "Introduza uma palavra: ";
    string palavra_lida;
    cin >> palavra_lida;

    for(string::size_type i = 0; i != palavra_lida.length(); ++i)
        cout << i << "º caractere é '" << palavra_lida[i] 
             << "'." << endl;
}

Experimente este programa.

Informação acerca dos caracteres

Para saber se um caractere é uma letra, pode-se usar a função isalpha(), para se converter um caractere para a sua versão minúscula (ou deixá-lo na mesma se não for uma letra) pode-se usar a função tolower().  A utilização destas funções requer que se acrescente a seguinte linha no início do programa:

#include <cctype>

4.1  Exemplo

#include <iostream>
#include <cctype>

using namespace std;

int main()
{
    cout << "Introduza um caractere: ";
    char caractere_introduzido;
    cin >> caractere_introduzido;

    if(isalpha(caractere_introduzido)) {
        cout << "É uma letra." << endl;
        if(isupper(caractere_introduzido)) {
            cout << "A letra é maiúscula." << endl;
            cout << "A versão minúscula é " 
                 << tolower(caractere_introduzido) << endl;
        }
    }
}