You are on page 1of 13

Resoluo dos Exerccios do Captulo VI

1. Implemente uma funo sem parmetros em C na qual se efetue a troca de dois


valores. Utilize-a em um programa executor de trocas de valores entre diversos
pares de variveis. Explique porque os problemas de redigibilidade, legibilidade e
confiabilidade seriam ainda mais graves nesse caso do que no exemplo 6.3.
int a, b; // variaveis globais
void troca(){
int aux;
aux = a;
a = b;
b = aux;
}
main(){
int c, d, e, f;
c = 0; d = 1; e = 2; f = 3;
a = c;
b = d;
troca();
c = a;
d = b;
a = e;
b = f;
troca();
e = a;
f = b;
}
Como no exemplo 6.3, a funo troca no possui parmetros, sendo necessrio
utilizar as variveis globais a e b para lhe conferir generalidade e possibilitar o seu
reuso em main.
Os problemas de redigibilidade, legibilidade e confiabilidade so ainda mais graves
dos que os do exemplo 6.3 por causa da necessidade de modificao dos valores das
variveis globais c, d, e e f aps a execuo da funo troca. Com isso, torna-se
necessrio escrever mais, a funcionalidade do programa fica ainda mais obscurecida
por envolver uma maior quantidade de atribuies e aumenta-se a possibilidade do
programador realizar alguma atribuio indevida ou esquecer alguma atribuio.

2. possvel implementar, para cada tipo primitivo, funes em JAVA nas quais
sejam trocados os valores dos seus parmetros formais? Caso sua resposta seja
afirmativa, implemente uma dessas funes e explique como funciona, destacando
como a troca feita. Em caso de resposta negativa, justifique. Existiria alguma
diferena na sua resposta caso a troca fosse realizada entre parmetros de um
mesmo tipo objeto? Justifique.
No. Java optou por fazer a passagem de tipos primitivos sempre por cpia para o
parmetro formal, o que impede que uma troca entre os parmetros formais se reflita
nos parmetros reais. No haveria diferena significativa na resposta se a troca fosse

realizada entre parmetros de um mesmo tipo objeto. Embora JAVA faa a passagem
de parmetros dos tipos objeto (no primitivos) por cpia de referncia, os efeitos da
troca continuariam sendo vlidos apenas internamente a funo, no se reflitindo nos
parmetros reais.

3. Um TAD (tipo abstrato de dados) definido pelo comportamento uniforme de um


conjunto de valores. Embora a linguagem C no suporte a implementao do
conceito de TADs, o programador pode simular o seu uso. Explique como isto
pode ser feito. Descreva os problemas com essa aproximao.
Para simular o uso de TADs em C, necessrio definir um tipo de dados simples e um
conjunto de operaes (subprogramas) que se aplicam sobre valores desse tipo, isto ,
subprogramas que tm parmetros desse tipo.
Normalmente, a implementao das operaes do TAD e quaisquer outras entidades
de computao necessrias para a implementao dessas operaes so definidas num
arquivo de implementao (.c). No arquivo de interface (.h), o tipo da estrutura de
dados definido e os prottipos dos subprogramas correspondentes s operaes do
TAD so declarados, para que sejam disponibilizados para os programadores usurios.
Assim, o programador usurio no necessita mais implementar o cdigo das
operaes do TAD, o que torna o cdigo mais legvel e redigvel, alm do cdigo
usurio no precisar ser alterado caso seja necessrio realizar uma alterao na
implementao do tipo ou nas suas operaes (desde que os cabealhos das operaes
no sejam modificados).
Os problemas com essa aproximao so que, alm dela no promover o
encapsulamento de dados e operaes em uma nica unidade sinttica, ela no impede
o uso indisciplinado do TAD. A operao de inicializao do TAD, por exemplo, deve
ser chamada explicitamente pelo programador. Caso o programador usurio esquea
ou no chame essa operao antes de qualquer outra, o uso correto do TAD ficar
comprometido. Alm disso, importante observar que ele pode realizar operaes
adicionais sobre o TAD alm das especificadas pelos subprogramas. Por exemplo, o
programador pode acessar diretamente a estrutura interna do TAD, quebrando o
ocultamento de informaes.

4. Considere uma funo em JAVA recebendo um objeto como nico parmetro e


simplesmente realizando a atribuio de null ao seu parmetro formal. Qual o
efeito dessa atribuio no parmetro real? Justifique.
Essa atribuio no produz qualquer efeito sobre o parmetro real correspondente, s
produzindo efeitos internos, uma vez que, em JAVA, as atribuies de valores
completos do tipo no-primitivo ao parmetro formal no produzem efeito no
parmetro real, sendo a passagem para tipos no-primitivos considerada, nesse caso,
unidirecional de entrada.

5. JAVA no permite a criao de funes com lista de parmetros varivel, isto ,


funes nas quais o nmero e o tipo dos parmetros possam variar, tal como a
funo printf de C. Como JAVA faz para possibilitar a criao da funo
System.out.println com funcionalidade similar funo printf de C? Como o
problema da falta de lista de parmetros varivel pode ser contornado de maneira
geral pelo programador JAVA em situaes nas quais esse tipo de caracterstica

pode ser til? Compare essa abordagem geral de JAVA com a adotada por C e
C++ em termos de redigibilidade e legibilidade.
A funo System.out.println de Java recebe sempre uma string como argumento. Ela
funciona de forma similar a printf por conta do uso combinado da operao de
concatenao (+) de strings e da realizao de converso implcita de tipos antes da
operao de concatenao. Tipos primitivos e objetos so convertidos implicitamente
para strings antes da realizao da concatenao (quando o outro argumento uma
string). Por exemplo, na chamada de System.out.println seguinte
int i =3;
System.out.println (teste: + i + : + new Float (4.3) + : + true);
o valor 3 de i convertido na string 3 antes de ser concatenado string teste.
Observe que esse processo se repete antes da realizao de cada operao de
concatenao. Em particular, o objeto Float criado convertido para uma string
atravs da chamada implcita da operao toString() dessa classe. Note que o valor
booleano (primitivo) tambm convertido implicitamente na string true.
Essa abordagem de JAVA pode causar confuses e erros. Na chamada seguinte de
System.out.println
int i =3;
int j =5;
System.out.println (i + j);
no haver converso de tipo e concatenao de strings. Como nenhum dos dois
argumentos string, JAVA far primeiro a operao aritmtica e depois a converso
do resultado para string, resultando na impresso da string 8 em vez de 35, como
algum pode eventualmente esperar.
O problema da falta de lista de parmetros varivel pode ser contornado de maneira
geral em JAVA atravs da utilizao de um parmetro formal vetor no qual no se
especifica o nmero de elementos do vetor. Se a funo recebe elementos de um
mesmo tipo, isso d flexibilidade para passar uma quantidade varivel de valores para
a funo em cada chamada. Se a funo necessita receber elementos de tipos
diferentes, basta definir o parmetro formal como um vetor de objetos. Essa soluo
to geral quanto a soluo de C e C++ e mais legvel, uma vez que no necessria
a utilizao de macros pr-definidas, cujo comportamento no amplamente
conhecido, como o caso em C e C++. Por outro lado, a redigibilidade um pouco
prejudicada pela necessidade de criar o vetor de objetos com os elementos que
precisam ser passados para a funo antes da sua chamada. A soluo mais geral de
JAVA pode ser observada no trecho de cdigo abaixo:
void f(Object[] x) {
for (int i = 0; i < x.length; i++) System.out.println (x[i]);
}
void g() {
Object[] a = new Object[] {
new Integer(12), new Float(1.5), new Boolean(true) };
f(a);
a = new Object[] {
new Integer(1), new Byte(15) };
f(a);
}

6. Uma das vantagens de se programar usando a tcnica de tipos abstratos de dados


(TADs) aumentar a modificabilidade dos programas. Isso ocorre porque a maior
parte das alteraes no cdigo do TAD no implicam em necessidade de
modificao do cdigo usurio. Indique em quais tipos de alteraes do cdigo do
TAD essa vantagem no pode ser aproveitada.
Em situaes nas quais ocorrem alteraes nos cabealhos (prottipos) dos
subprogramas que compem a interface, o cdigo usurio, que utiliza esses
subprogramas, tem que ser modificado. Isso tambm ocorre se existem atributos da
estrutura do TAD que so pblicos, isto , que fazem parte da interface. Quando esses
atributos so alterados, o cdigo usurio, que utiliza esses atributos, tem que ser
modificado.

7. O uso de parmetros em um subprograma visa aumentar as possibilidades de reuso


desse subprograma. Normalmente, os valores dos parmetros correspondem a
dados manipulados pelo subprograma. Contudo, os parmetros podem servir
tambm para alterar a funcionalidade do subprograma, tornando sua aplicao
mais abrangente e aumentando sua possibilidade de reuso. Mostre, atravs de um
exemplo em C, como valores do tipo ponteiro para funo podem ser utilizados
como parmetros para tornar um determinado cdigo mais reusvel. Discuta como
esse problema seria resolvido sem o uso do parmetro ponteiro para funo.
Analise e compare as duas solues propostas em termos de redigibilidade,
legibilidade, eficincia e reusabilidade.
Exemplo em C de uma funo que soma dois termos inteiros com o resultado da
aplicao de uma funo arbitrria sobre os mesmos.
#include <stdio.h>
int multiplica (int a, int b) {
return (a * b);
}
int maluca (int a, int b) {
return (2 * a + 5 * b);
}
int aplicacao (int a, int b, int (*f) (int, int)) {
return (a + b + (*f) (a, b));
}
main () {
int x = 1, y = 2, resultado;
resultado = aplicacao (x, y, maluca);
printf ("resultado = %d", resultado); //imprime 15
resultado = aplicacao (x, y, multiplica);
printf ("\nresultado = %d", resultado); //imprime 5
}
No programa acima, a no utilizao do parmetro ponteiro para funo implicaria na
necessidade da construo de diferentes funes, do mesmo formato da funo
aplicacao, porm especficas para cada funcionalidade desejada.
A utilizao de ponteiros para funes como parmetros reduz a legibilidade, devido
necessidade de se utilizar ponteiros e suas operaes, porm melhora a redigibilidade
e a reusabilidade, pois um mesmo subprograma pode ser utilizado para atingir

diferentes funcionalidades, como o caso da funo aplicacao, em um mesmo


programa ou em programas diferentes. Com relao eficincia ocorre uma pequena
perda em funo da necessidade de dereferenciamento do ponteiro na chamada de
funo dentro de aplicacao.

8. Contrastando com a maioria das LPs imperativas, em C possvel criar funes


cuja lista de parmetros varivel (tome como exemplo, a funo printf). Analise
a abordagem adotada por C em comparao a:
abordagem adotada por MODULA-2, que no permite a existncia de
subprogramas com lista de parmetros varivel (enfoque a comparao nos
conceitos de redigibilidade e confiabilidade)
abordagem adotada por PASCAL, que permite a existncia de lista de
parmetros varivel para funes pr-definidas da linguagem, tais como
read e readln, mas no permite ao programador criar subprogramas com
lista de parmetros varivel (enfoque a comparao nos conceitos de
reusabilidade e ortogonalidade)
A abordagem adotada por C apresenta melhor redigibilidade pois em MODULA-2
necessrio criar uma funo distinta para cada contexto no qual o tipo e nmero dos
parmetros varia. J em C, em muitos casos, pode-se utilizar uma mesma funo
nestes contextos. Tomando por exemplo a funo printf de C, tem-se que, como essa
funo usada nos mais variados contextos, qualquer limitao no seu nmero e tipo
de parmetros a tornaria insuficiente para atender a todas as possveis demandas.
Assim, ela deveria ser reescrita, em MODULA-2, cada vez que fosse necessria em
aplicaes diferentes. Com relao confiabilidade, a abordagem adotada por
MODULA-2 mais confivel, pois na abordagem adotada por C, no possvel
verificar os tipos dos parmetros em tempo de compilao. Nesse caso, tarefa
exclusiva dos programadores garantir o funcionamento correto do subprograma.
Comparando as abordagens adotadas por C e Pascal, podemos concluir que C
melhor tanto na questo da ortogonalidade, uma vez que no restringe a utilizao de
lista de parmetros variveis a alguma funes da linguagem, como o faz Pascal,
quanto na questo da reusabilidade, pois permite o reso de uma maior quantidade de
funes do que Pascal.

9. Tipos Abstratos de Dados (TADs) so uma ferramenta poderosa de projeto e


programao. Descreva, de uma forma geral, como a programao com TADs
pode ser feita em C, ADA e C++. Exemplifique com a descrio do tipo abstrato
de dados fila de elementos inteiros (no necessrio implementar as operaes da
fila). Compare as trs abordagens em termos de encapsulamento, ocultamento de
informao, confiabilidade do uso e necessidade de alterao do cdigo fonte
usurio quando ocorrem alteraes no cdigo do TAD.
C:
A linguagem C no suporta a implementao do conceito de TADs, mas o
programador pode simular o seu uso. Para simular o uso de TADs em C, necessrio
definir um tipo de dados simples e um conjunto de operaes (subprogramas) que se
aplicam sobre valores desse tipo. A implementao das operaes do TAD e
quaisquer outras entidades de computao necessrias para a implementao dessas
operaes so definidas num arquivo de implementao (.c). No arquivo de interface

(.h), o tipo da estrutura de dados definido e os prottipos dos subprogramas


correspondentes s operaes do TAD so declarados, para que sejam
disponibilizados para os programadores usurios.
Exemplo em C arquivo de interface (.h):
typedef struct no {
int info;
struct no *prox;
}No;
typedef struct fila {
No *ini, *fim;
}Fila;
Fila Inicia ();
Fila Insere (Fila fil, int elem);
Fila Elim (Fila fil);
int Info (Fila fil);
int Vazia (Fila fil);
void Destroi (fila fil);
ADA:
ADA usa uma abordagem que envolve a definio do TAD em duas unidades
sintticas do programa. Em uma unidade definida a interface do TAD, enquanto na
outra definida a sua implementao. Somente o que definido no arquivo de
interface exportado. Isso significa que os programadores usurios do TAD s tero
acesso s entidades definidas nessa unidade. A unidade de implementao contm
detalhes a respeito de como as entidades da interface so implementadas e tambm
contm outras entidades utilizadas para auxiliar a implementao das entidades de
interface.
Exemplo em ADA unidade de interface
package fila_inteiros is
type Fila is limited private;
procedure Inicia (fil: out Fila);
procedure Insere (fil: in out Fila; elem: in integer);
procedure Elim (fil: in out Fila);
function Info (fil: in Fila) return integer;
function Vazia (fil: in Fila) return boolean;
private:
max: constante integer := 100;
type Fila is record
ini: integer;
elem: array (1 .. max) of integer;
fim: integer;
end record;
end fila_inteiros;
C++:
C++ utiliza o conceito de classe para implementar TADs. As classes permitem ao
programador criar um novo tipo de dados, incluindo de uma forma encapsulada tanto
a representao do novo tipo quanto as operaes associadas a ele. As classes

oferecem proteo dos dados do tipo utilizando especificadores de acesso. Por


exemplo, em C++, os dados da classe e suas operaes podem ser privados (s so
visveis para a implementao das operaes do TAD) ou pblicos (so visveis para
qualquer trecho do programa).
As classes tornam especiais as operaes construtoras, que so identificadas pelo seu
nome, que deve ser o mesmo da sua classe (resolvendo o problema da inicializao de
TADs, j que, quando um objeto criado, essa operao chamada
automaticamente), e destrutoras (tambm identificada pelo seu nome que da forma
~nome_da_classe), e oferecem suporte aos conceitos de herana e polimorfismo,
fundamental para a orientao a objetos.
Exemplo em C++ - arquivo de interface (.h)
class Fila {
struct No {
int info;
struct No *prox;
}
No *ini, *fim;
public:
Fila ();
Insere (int elem);
Elim ();
int Info ();
int Vazia ();
~Fila ();
}
Enquanto a abordagem de C no atende satisfatoriamente a propriedade de
encapsulamento, pois a estrutura de dados do TAD e suas operaes no so definidas
em uma nica unidade sinttica, ADA e C++ satisfazem esse requisito. De maneira
anloga, ADA e C++ possibilitam o ocultamento de informao, o que no possvel
em C. Com relao confiabilidade, C++ que mais satisfaz essa propriedade. Em
ADA, eventualmente, operaes podem ser chamadas sem que a operao de
inicializao tenha sido realizada. Em C, alm de poder ocorrer o mesmo problema de
ADA, possvel que o programador usurio altere os dados do TAD sem o uso das
operaes definidas para o TAD. A alterao do cdigo fonte usurio s necessria
em C++ e ADA quando os cabealhos das operaes pblicas ou atributos pblicos
so alterados. Em C, a alterao pode ser necessria sempre que h modificao nos
atributos do TAD, uma vez que todos eles so pblicos.
10. Considere o seguinte programa escrito na sintaxe de C:
void calculoMaluco (int a, int b) {
a = a + b;
b = a + b;
}
void main() {
int valor = 0;
int lista [5] = { 1, 3, 5, 7, 9 };
calculoMaluco ( valor, lista [valor] );
}

Determine qual o valor das variveis valor e lista aps a execuo do programa,
supondo que:

a) A direo da passagem de parmetros unidirecional de entrada varivel, o


mecanismo por cpia e o momento de passagem definido pelo modo normal.
b) A direo bidirecional de entrada e sada, o mecanismo por referncia e o
momento normal.
c) A direo bidirecional de entrada e sada, o mecanismo por referncia e o
momento por nome.
Explique os resultados alcanados.
a) Em main, antes da chamada da funo calculoMaluco, tem-se valor = 0 e lista =
{1, 3, 5, 7, 9}. Na chamada da funo calculoMaluco, o parmetro formal a recebe
valor = 0, ou seja, a = 0 e o parmetro formal b recebe lista[0] = 1, ou seja, b = 1
(modo normal). Em calculoMaluco, os valores de a e b mudam para a = 1 e b = 2,
mas esses valores no so repassados aos parmetros reais valor e lista[0], pois a
passagem de parmetros unidirecional de entrada varivel e o mecanismo por
cpia. Assim, os valores das variveis valor e lista aps a execuo do programa so:
valor = 0 e lista = {1, 3, 5, 7, 9}.
b) Em main, antes da chamada da funo calculoMaluco, tem-se valor = 0 e lista =
{1, 3, 5, 7, 9}. Na chamada da funo calculoMaluco, o parmetro formal a passa a
referenciar valor = 0 e o parmetro formal b passa a referenciar lista[0] = 1 (modo
normal e mecanismo por referncia). Em calculoMaluco, os valores de a e b mudam
para a = 1 e b = 2, alterando, respectivamente, os valores de valor e lista[0]
(mecanismo por referncia e passagem bidirecional de entrada e sada). Assim, os
valores das variveis valor e lista aps a execuo do programa so: valor = 1 e lista
= {2, 3, 5, 7, 9}.
c) Em main, antes da chamada da funo calculoMaluco, tem-se valor = 0 e lista =
{1, 3, 5, 7, 9}. Na primeira linha da funo calculoMaluco, o parmetro formal a passa
a referenciar valor e o parmetro formal b passa a referenciar lista[valor] (modo por
nome e mecanismo por referncia). Logo a instruo passa a ser valor = valor + lista
[valor]. Na execuo da instruo dessa linha, o parmetro formal valor passa a valer
1 pois valor era igual a zero e lista[0] igual a 1. Na segunda linha da funo
calculoMaluco, o parmetro formal a passa a retornar 1 (o valor corrente de valor) e o
parmetro formal b passa a referenciar lista[1], o que vale 3 (modo por nome e
mecanismo por referncia). Na execuo da instruo dessa linha, o parmetro formal
b e, consequentemente, o parmetro real lista[1] tem seu valor modificado para 4.
Assim, os valores das variveis valor e lista aps a execuo do programa so: valor
= 1 e lista = {1, 4, 5, 7, 9}.

11. Os dois trechos de cdigo seguintes apresentam definies (em arquivos .h) do
tipo abstrato de dados BigInt em C e C++, respectivamente. BigInt um tipo de
dados que permite a criao de nmeros inteiros maiores que long.
// C
struct BigInt {
char* digitos;
unsigned ndigitos;

};
struct BigInt criaBigIntC (char* c);
// cria a partir de string
struct BigInt criaBigIntN (unsigned n);
// cria a partir de unsigned
struct BigInt criaBigIntB (struct BigInt b); // cria a partir de outro BigInt
void atribui (struct BigInt* b1, struct BigInt* b2);
struct BigInt soma (struct BigInt b1, struct BigInt b2);
void imprime (FILE* f, struct BigInt b);
void destroi (struct BigInt b);
// C++
class BigInt {
char* digitos;
unsigned ndigitos;
public:
BigInt (const char* c);
BigInt (unsigned n = 0);
BigInt (const BigInt& b);
void atribui (const BigInt& b);
BigInt soma (const BigInt& b) const;
void imprime (FILE* f = stdout) const;
~ BigInt();
};

Compare essas definies em termos de encapsulamento, proteo dos dados e


confiabilidade das operaes de inicializao e terminao das instncias desse
TAD. Justifique sua resposta.
A operao atribui da classe BigInt tambm poderia ser definida atravs do
seguinte prottipo:
void atribui(BigInt);
Compare essa definio com a usada na classe BigInt em termos de eficincia de
execuo e confiabilidade na proteo dos dados do parmetro formal. Explique
sua resposta.
A definio de C++ tem melhor encapsulamento porque os atributos e as operaes de
BigInt so definidas em uma nica entidade sinttica. Ela tambm possui maior
proteo de dados porque os atributos de BigInt so privados, enquanto na verso de
C eles so pblicos. A confiabilidade das operaes de inicializao e terminao
tambm maior em C++ porque essas operao so garantidamente chamadas no
incio e ao final da vida dos objetos BigInt. Isso no ocorre com a implementao em
C pois o programador usurio deve cham-las explicitamente, o que possibilita seu
esquecimento.
Na operao void atribui (const BigInt& b); o parmetro b tem passagem
unidirecional de entrada constante por referncia. Na operao void atribui(BigInt); o
parmetro b tem passagem unidirecional de entrada constante por cpia. Portanto, em
termos de proteo de dados do parmetro formal elas se equivalem (ambas so
passagem unidirecional de entrada constante). O que as diferencia a eficincia de
execuo, que melhor na por referncia pois no existe a necessidade de realizao
de cpia dos dados nem da chamada do construtor de cpia.

12. Ao se modificar a estrutura de dados de uma classe em C++, ainda que mantida a
mesma interface (isto , as assinaturas das operaes pblicas da classe continuam
idnticas s existentes antes da alterao), necessrio recompilar no apenas o
cdigo da prpria classe, mas tambm os programas usurios dessa classe.
Explique porque isso ocorre levando em conta que no h alteraes no cdigo
fonte dos programas usurios. Explique como JAVA evita a necessidade de
recompilao nesses casos. Apresente razes para justificar a no incorporao
dessa caracterstica em C++?
A recompilao do cdigo usurio necessria pois a alterao na estrutura de dados
modifica o tamanho do espao a ser armazenado pelo cdigo usurio dessa estrutura.
JAVA sempre aloca objetos no monte, logo o cdigo usurio s necessita alocar uma
referncia para o objeto na pilha. Como a interface com o construtor no foi alterada e
ele quem aloca o espao no monte, no haver problemas na mudana da estrutura.
C++ no incorpora o mecanismo implementado em JAVA porque a alocao no
monte tem desempenho menos eficiente que a alocao na pilha.

13. Execute o seguinte trecho de cdigo em C++, mostrando o seu resultado.


void incrementa (int& x, int& y) {
x = x + y;
y++;
}
main ( ) {
int a [ ] = { 1, 2, 3 };
for ( int i = 0; i < 3; i++ ) {
incrementa ( a [ i ], a [ 1 ] );
cout << a [ i ] << "\n" ;
}
}
Explique como o resultado foi produzido. A execuo desse cdigo produz algum
efeito estranho prejudicial a legibilidade? Justifique sua resposta.
Em main, antes da entrada no for, tem-se a = {1, 2, 3}. Na primeira vez que o for
executado, os parmetros reais de incrementa so a[0] = 1 e a[1] = 2. Eles so
passados por referncia, assim, em incrementa, x e y so referncias para a[0] = 1 e a
[1] = 2. Na primeira instruo, x, e consequentemente a[0], tem seu valor alterado
para 3. Na segunda, y, e consequentemente a[1], tem seu valor alterado para 3. Logo,
ao final da primeira chamada a = {3, 3, 3} e o valor impresso 3.
Na segunda vez que o for executado, os parmetros reais de incrementa so
a
[1] = 3 e a[1] =3. Eles so passados por referncia, assim, em incrementa, x e y so
referncias para a[1] =3. Na primeira instruo, x, e consequentemente a[1], tem seu
valor alterado para 6. Na segunda, y, e consequentemente a[1], tem seu valor alterado
para 7. Logo, ao final da segunda chamada a = {3, 7, 3} e o valor impresso 7.
Na terceira vez que o for executado, os parmetros reais de incrementa so
a
[2] = 3 e a[1] = 7. Eles so passados por referncia, assim, em incrementa, x e y so
referncias para a[2] =3 e a[1] = 7. Na primeira instruo, x, e consequentemente a
[2], tem seu valor alterado para 10. Na segunda, y, e consequentemente a[1], tem seu

10

valor alterado para 8. Logo, ao final da segunda chamada a = {3, 8, 10} e o valor
impresso 10.
A execuo desse cdigo produz um efeito estranho prejudicial legibilidade. Ocorre
sinonmia quando a varivel i assume o valor 1, no for, pois os dois parmetros
formais da funo incrementa so associados ao mesmo parmetro real a[1], o que
dificulta o entendimento do programa.

14. Em uma LP, o momento da avaliao dos parmetros reais, durante a passagem de
parmetros, pode ser por definido pelo modo normal (eager), por nome (by name)
ou preguioso (lazy). Explique o significado de cada um desses modos. Execute
trs vezes o programa C seguinte, supondo que a linguagem adotasse, em cada
execuo, um tipo diferente de modo de avaliao. Explique os resultados
alcanados.
void avalia (int c) {
int i;
for (i = 0; i < 3; i++) {
printf ("%d\n", c);
}
}
void main ( ) {
int j = 0;
avalia (j++);
}
No modo normal (ou eager) a avaliao dos parmetros reais ocorre no momento da
chamada do subprograma. No modo por nome (by name) a avaliao ocorre em todos
os momentos em que o parmetro formal usado. No modo preguioso (lazy) a
avaliao ocorre no primeiro momento em que o parmetro formal usado.
Execuo pelo modo normal (eager):
Resultado:

0
0
0
Como a avaliao dos parmetros normal, o valor passado para c ser resultado da
avaliao retornado pela expresso j++ antes da execuo de avalia. Portanto, c = 0.
Execuo pelo modo por nome (by name):
Resultado:

0
1
2
Explicao: No modo de avaliao por nome, no momento em que o parmetro
formal c utilizado pela primeira vez na funo avalia, tem-se c = 0 e j torna-se 1.
Na utilizao de c pela segunda vez tem-se c = 1 e j torna-se 2. Na utilizao de c
pela terceira vez tem-se c = 2. O valor de j muda a cada avaliao do parmetro
real, o que acontece sempre que o parmetro formal utilizado. Isso faz com que o
valor do parmetro formal impresso seja diferente a cada impresso.
Execuo pelo modo preguioso (lazy):
Resultado:

0
0

11

0
Na avaliao preguiosa, o parmetro real j++ avaliado no momento em que o
parmetro formal c utilizado pela primeira vez e permanece assim at o final da
execuo da funo. Logo, c = 0 em todas os passos da repetio.
15. Descreva como deve ser feita a operao de desalocao de memria em um tipo
abstrato de dados lista de inteiros em C, C++ e JAVA. Compare as diferentes
abordagens adotadas por essas LPs na implementao e uso dessa operao em
termos de redigibilidade, confiabilidade e eficincia.
Em C necessrio que o programador crie uma funo para percorrer cada n da lista
e v desalocando-os. Essa funo deve ser chamada explicitamente quando a lista
necessita ser desalocada. C++ utiliza uma funo especial destrutora da classe, a qual
deve ser implementada pelo programador. Essa funo chamada implicitamente
quando se encerra o tempo de vida da lista. Em JAVA, a desalocao feita
automaticamente pelo coletor de lixo, no existindo necessidade de implementao de
uma operao destrutora ou invocao de qualquer mtodo.
Em termos de redigibilidade, a melhor soluo a de JAVA pois o programador no
necessita redigir nada. C++ requer a implementao da funo destrutora, mas no
necessita da redao de cdigo para chamada dessa funo. C a soluo de menor
redigibilidade pois o programador necessita implementar a funo de desalocao e
tambm cham-la explicitamente no cdigo usurio.
Em termos de confiabilidade, a soluo de JAVA tambm superior, pois o
programador no necessita definir como os ns lista devem ser desalocados, nem
quando isso deve ser feito. O prprio sistema se encarrega dessas tarefas. A soluo de
C++ mais confivel do que a de C porque ela garante que a operao de desalocao
ser garantidamente chamada ao final do tempo de vida da lista.
Por outro lado, em termos de eficincia, C e C++ podem superar JAVA pois deixam a
cargo do programador a funo de desalocar memria quando esta no mais
necessria. Com isso, um bom programador pode explorar o contexto para dizer como
e em qual momento mais eficiente fazer a operao de desalocao.

16. Qualifique os tipos de passagem de parmetros oferecidos por C, C++ e JAVA em


termos da direo da passagem e do mecanismo de passagem. Compare-os em
termos de confiabilidade e eficincia.
C
Direo da passagem: A linguagem C s oferece passagem unidirecional de entrada.
Embora se possa usar a palavra const na definio de um parmetro, a incluso dessa
palavra no torna esse parmetro necessariamente constante, uma vez que os
compiladores podem simplesmente ignor-la. Portanto, pode-se considerar que C
somente oferea passagem unidirecional de entrada varivel.
Mecanismo de passagem: C oferece apenas o mecanismo de passagem por cpia.
C++
Direo da passagem: C++ oferece as passagens unidirecional de entrada varivel ou
constante e bidirecional de entrada e sada.
Mecanismo de passagem: C++ adota tanto o mecanismo de passagem por cpia
quanto por referncia. Ela usa o operador & para designar um parmetro passado por
referncia, diferenciando-o assim dos parmetros que usam passagem por cpia.
JAVA

12

Direo da passagem: JAVA oferece passagem unidirecional de entrada varivel ou


constante para tipos primitivos. Para tipos no-primitivos, a passagem pode ser
considerada unidirecional de entrada varivel ou constante, pois as atribuies de
valores completos do tipo no-primitivo ao parmetro formal no produzem efeito no
parmetro real, ou bidirecional, pois atribuies aos componentes do parmetro
formal tm efeito sobre os componentes do parmetro real.
Mecanismo de passagem: Quando a passagem de tipos primitivos, ocorre cpia.
Quando a atribuio de tipos no-primitivos passa-se uma cpia da referncia.
Comparando os mecanismos tem-se que, em geral, a passagem de um parmetro que
contenha um grande volume de dados, como um vetor, mais eficiente por meio do
mecanismo de referncia do que o de cpia. Ao usar o mecanismo de cpia,
necessrio alocar espao adicional suficiente para repetir todo o volume de dados do
parmetro real. Alm disso, necessrio, realizar a cpia dos valores do parmetro
real para o formal e vice-versa. Isso contrastado com a passagem por referncia, a
qual demanda apenas alocao de espao adicional para armazenar um ponteiro. Alm
disso, no necessrio copiar quaisquer dados.
Por outro lado, como o mecanismo de referncia baseia-se no acesso indireto aos
dados do parmetro real, em uma implementao distribuda, o corpo do subprograma
pode estar sendo executado num processador remoto, distante dos dados. Nessa
situao, o acesso indireto pode ser menos eficiente que o mecanismo de cpia
seguido de acesso local.
Uma outra desvantagem do mecanismo de referncia a possibilidade de ocorrncia
de sinonmia. Isso pode ocorrer na passagem por referncia quando dois parmetros
formais so associados ao mesmo parmetro real ou quando o subprograma faz uso de
variveis globais e um parmetro formal referencia uma dessas variveis. Isso pode
ser difcil de identificar, em caso de engano, e entender quando necessrio,
prejudicando a legibilidade e a confiabilidade no cdigo.
Alm disso, o mecanismo de cpia apresenta boa confiabilidade porque facilita a
recuperao do estado prvio do programa quando um determinado subprograma
termina inesperadamente. Uma vez que as atualizaes executadas pelo subprograma
so efetuadas sobre o parmetro formal e s so repassadas ao real no final da
execuo, uma interrupo inesperada do subprograma no afeta, em princpio, o
estado das variveis do programa.
De forma geral, pode-se dizer que C++ apresenta a maior variedade de tipos de
passagem de parmetros, oferecendo, em particular, a passagem unidirecional de
entrada constante por referncia que mais confivel do que a passagem de objetos
em JAVA e mais eficiente do que a passagem de tipos compostos por valor em C.

13

You might also like