Você está na página 1de 7

Pontifícia Universidade Católica de Minas Gerais

Bacharelado em Sistemas de Informação


Algoritmos e Estruturas de Dados - 2009/1
Italo Stefani

Laboratório 08 – Modularização
Para a resolução deste trabalho, lembre-se organizar seu código seguindo os critérios:

• Nomes sugestivos para variáveis;

• Separar trechos de código pelas suas atividades em métodos e funções;

• Comentar os trechos de código conforme sua atividade.

Escopo de variáveis

Escopo de uma variável pode ser compreendido como sendo a região de um programa em que uma variável
pode ser utilizada. Uma variável passa a existir no momento de sua declaração e pode ser utilizada nos
comandos seguintes até o final de seu escopo.

O escopo de uma variável é definido pela região onde ela foi declarada. Em C#, uma região é delimitada por
chaves, como em funções, comando condicionais e laços de repetição.

Podemos classificar o escopo de uma variável de duas formas:

• Escopo Local

• Escopo Global
Quando uma variável é declarada dentro de um método, dizemos que essa variável possui escopo local, e
podemos referenciá-la como variável local. Até agora, trabalhamos apenas com variáveis com escopo local,
pois eram todas declaradas dentro do método principal (Main). Por exemplo, quando declaramos uma
variável maior dentro do método encontraMaior, apenas podemos utilizar essa variável dentro deste
método. Outros métodos não têm acesso à maior, mesmo se for o método que chama encontraMaior.

Em C#, os métodos são declarados dentro da região indicada pela palavra class. Se declararmos uma variável
na mesma região em que os métodos são declarados, ela possuirá escopo global, e podemos referenciá-la
como variável global. Isso significa que ela pode ser acessada por todos os métodos que são definidos nessa
mesma região.

Exemplo

Considere
o
seguinte
problema:
dado
três
números
inteiros,
quero
saber
se
o
maior
deles
é
maior
que
a
soma
dos

menores.
O
código
a
seguir
apresenta
uma
possível
solução
utilizando
métodos.
Repare
nas
declarações
de

variáveis
com
escopo
local
e
escobo
global.

using System;
namespace ATPLab {
class Program {

/* ### VARIAVEIS GLOBAIS ### */


static int num1 = 0;
static int num2 = 0;
static int num3 = 0;

// Le os numeros
// Variaveis num1, num2 e num3 existem no escopo global
static void leNumeros() {
Console.Write("\n Digite o primeiro número: ");
num1 = int.Parse(Console.ReadLine());
Console.Write("\n Digite o segundo número: ");
num2 = int.Parse(Console.ReadLine());
Console.Write("\n Digite o terceiro número: ");
num3 = int.Parse(Console.ReadLine());
}
// Encontra o maior numero
// Variavel maior faz parte do escopo local
// Variaveis num1, num2 e num3 existem no escopo global
static int encontraMaior() {
int maior = num1;
if (num2 > maior) {
maior = num2;
}
if (num3 > maior) {
maior = num3;
}
return maior;
}
// Soma os numeros menores
// Variavel soma faz parte do escopo local
// Variaveis num1, num2 e num3 existem no escopo global
static int somaMenores(int maior) {
int soma = 0;
soma = num1 + num2 + num3 - maior;
return soma;
}
// Compara o maior com o resultado da soma
// Variaveis maior e soma existem no escopo local,
// pois sao definidas como parametros
static void comparaMaior(int maior, int soma) {
if (maior > soma) {
Console.Write("\n SIM ");
}
else {
Console.Write("\n NAO ");
}
}

static void Main(string[] args) {


int maior = 0; // escopo local
int soma = 0; // escopo local

leNumeros();
maior = encontraMaior();
soma = somaMenores(maior);
comparaMaior(maior, soma);

Console.ReadLine();
}
}
}
Na solução apresentada as variáveis num1, num2 e num3 são “visíveis”, ou seja, podem ser acessadas a partir
de qualquer método. Assim, os métodos leNumeros e encontraMaior as utilizam sem problemas.

Analisando o método encontraMaior podemos notar que a variável maior é declara no escopo local. Assim,
ela apenas pode ser utilizada dentro deste método. O mesmo ocorre para a variável soma dentro do método
somaMenores.

É importante notar que os parâmetros de um método são variáveis de escopo local, como acontece em
comparaMaior. Nesse método, podemos outro detalhe no que diz respeito a escopo de variáveis. Sabemos que
uma variável deve ter nome único. Então, como podemos definir 3 variáveis com o nome maior? No nosso
exemplo, temos essa variável definida nos métodos encontraMaior, comparaMaior e Main. Isso é Possível
pois uma variável deve ter nome único dentro de um escopo. Logo, temos três variáveis diferentes com o
mesmo nome, mas uma não existe no mesmo escopo da outra.

Conflito de nomes
Já sabemos que uma variável de escopo global existe em todo o programa, e que uma variável de escopo
local existe apenas no escopo onde foi declarada, por exemplo dentro de um método. Porém, se uma variável
global for definida com o mesmo nome que uma variável local, o que acontece? Veja o exemplo a seguir.
using System;
namespace ATPLab {
class Program {

/* ### VARIAVEIS GLOBAIS ### */


static int maior = 0;

// Encontra o maior entre dois numeros


// Variavel num1, num2 e maior faz parte do escopo local
static int encontraMaior(int num1, int num2) {
int maior = num1;
if (num2 > maior) {
maior = num2;
}
return maior;
}

static void Main(string[] args) {


int valor1 = 0;
int valor2 = 0;

Console.Write("\n Digite o primeiro número: ");


valor1 = int.Parse(Console.ReadLine());
Console.Write("\n Digite o segundo número: ");
valor2 = int.Parse(Console.ReadLine());

maior = encontraMaior(valor1,valor2);

Console.ReadLine();
}
}
}
É fácil notar que maior dentro do método principal (Main) se refere à variável global maior. Porém, se
analisarmos o método encontraMaior, podemos notar que existe uma variável também com nome maior.
Não deveria dar erro? Se utilizarmos maior dentro do método encontraMaior, estamos lidando com qual
definição, a local ou a global?

Quando isso ocorre, dizemos que houve uma colisão de nomes, porém na maioria das linguagens de
programação, inclusive em C#, a definição local prevalece sobre a definição global. Então, encontraMaior
não está nem aí para a variável global maior. Esse método cria sua própria variável maior local a utiliza em
seu corpo.

Passagem de parâmetros por valor e por referência

Já vimos que métodos podem ter parâmetros e que eles nada mais são do que variáveis locais. Os parâmetros
servem para injetarmos valores dinâmicamente auxiliando na reusabilidade do método.

Quando fazemos uma chamada de um método passando uma variável, como fizemos no exemplo anterior,
passamos na verdade uma cópia de seu valor. Isso é chamado de passagem de parâmetro por valor.

Veja o exemplo a seguir:


// Encontra o maior entre dois numeros
static int encontraMaior(int num1, int num2) {
if (num2 > num1) {
num1 = num2;
}
return num1;
}

Neste exemplo aplicamos o mesmo algoritmo conhecido anteriormente para encontrar o maior entre dois
números, porém eliminamos o uso da variável menor. Para isso, assumimos que o num1 é o maior elemento.
Se num2 for maior que num1, num1 recebe o valor de num2. Por fim, retornamos o maior valor, que estará
armazenado em num1. Se fizermos a seguinte chamada no método principal:
maior = encontraMaior(valor1,valor2);

Temos a passagem de parâmetros por valor e num1 e num2 recebem cópias dos valores de valor1 e valor2.
Não interessa o que seja feito com num1 e num2 dentro do método encontraMaior, valor1 e valor2 terão
seus valores preservados no método principal.

A linguagem C# fornece um recurso que nos permite alterar o valor de uma variável que foi passada como
parâmetro para um método. Neste caso, utilizamos a passagem de parâmetro por referência, quando o
parâmetro do método passa a ser uma referência para a variável do lado de fora. Para isso, devemos indicar,
com a palavra ref, que o parâmetro receberá uma referencia. Na chamada do método devemos também
utilizar ref para indicar a passagem por referência.

Para o método a seguir:


// Encontra o maior entre dois numeros
// Variavel num1 eh uma referencia
static int encontraMaior(ref int num1, int num2) {
if (num2 > num1) {
num1 = num2;
}
return num1;
}

Devemos utilizar a chamada:


maior = encontraMaior(ref valor1,valor2);

Note a presença da palavra ref na definição e na chamada do método encontraMaior.

Execute o programa a seguir e analise os resultados:


using System;
namespace ATPLab {
class Program {

// Encontra o maior entre dois numeros


static int encontraMaior(int num1, int num2) {
if (num2 > num1) {
num1 = num2;
}
return num1;
}

static void Main(string[] args) {


int maior = 0;

valor1 = 10;
valor2 = 20;

maior = encontraMaior(valor1,valor2);
Console.WriteLine("Valor 1 = " + valor1 + " e Valor 2 = " + valor2);
Console.ReadLine();
}
}
}

Altere o programa para que exista passagem por referência em num1. Percebeu a diferença entre passagem
por referência e por valor?
Passando vetor e matriz como parâmetro

Já vimos como definir e utilizar passagem de parâmetro por valor e referência. Porém, para vetores e
matrizes a passagem é SEMPRE por referência e não há a necessidade de indicar via palavra chave ref.

ATENÇÃO: se utilizarmos a palavra ref na passagem de vetor e matriz como parâmetro podemos ter um
resultado não esperado. Portanto, não usem (por enquanto!!).

Execute o programa a seguir e analise o resultado:


using System;
namespace ATPLab {
class Program {

// Gera valores pares para um vetor


static void geraPar(int [] v) {
for (int i=0; i<v.Length; i++) {
v[i] = i*2;
}
}

// Gera valores impares para um vetor


static void geraPar(int [] v) {
for (int i=0; i<v.Length; i++) {
v[i] = i*2+1;
}
}

// Imprime valores de um vetor


static void imprime(int [] v) {
for (int i=0; i<v.Length; i++) {
Console.Write(vetor[i] + " ");
}
Console.WriteLine();
}

static void Main(string[] args) {


int [] vetor = new int [10];

geraImpar(vetor);
imprimeVetor(vetor);
geraPar(vetor);
imprimeVetor(vetor);

Console.ReadLine();
}
}
}
Trabalho

Altere o trabalho de arquivos, onde eram manipuladas matrizes lidas de arquivos textos, de forma que as
operações sejam realizadas via métodos. As seguintes atividades devem ser realizadas:

• Carregar matriz de um arquivo;

• Salvar matriz em um arquivo;

• Somar duas matrizes;

• Multiplicar duas matrizes.


Seu trabalho deve conter o seguinte esqueleto:
using System;
namespace ATPLab {
class Matrizes {

// Dado um nome de arquivo, retornar uma matriz com os valores lidos.


// As dimensões da matriz devem ser retornadas por referencia.
static int [,] carregarMatriz(string arquivo, ref int linhas, ref int colunas)
{
}

// Dada uma matriz, suas dimensões e um nome de arquivo,


// gravar a matriz no arquivo.
static void salvarMatriz(int [,] matriz, int linhas, int colunas, string arquivo)
{
}

// Retorna a matriz resultante da soma de duas matrizes


static int [,] somarMatrizes(int [,] matrizA, int [,] matrizB, int linhas, int colunas)
{
}
// Retorna a matriz resultante da multiplicacao de duas matrizes.
// linasC e colunasC sao as dimensoes da matriz resultante.
// colunasA eh a quantidade de colunas da matriz A, que eh o mesmo valor de linhas de B.
static int [,] multiplicarMatrizes
(int [,] matrizA, int [,] matrizB, int linhasC, int colunasC, int colunasA)
{
}

// Imprime uma matriz.


static void imprimeMatriz(int [,] matriz, int linhas, int colunas)
{
}

static void Main(string[] args) {


}
}
}

Você também pode gostar