Buscar

CLP_ Cap 1 - 5

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 19 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 19 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 19 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Capítulo 1 - Introdução 
 
1. Identifique problemas de legibilidade e redigibilidade nas LPs que conhece. 
Verifique se existem casos nos quais essas propriedades são conflitantes. 
 
Problemas de Legibilidade 
 
C: Possui características que são fáceis de utilizar, mas que deixam o código ilegível. O 
desvio incondicional "goto" e o operador "*" que tanto pode significar a operação de 
multiplicação quanto operações de manipulação de ponteiros. 
 
Problemas de Redigibilidade 
 
Visual Basic: Não é possível declarar diversas variáveis de mesmo tipo especificando o tipo 
somente uma vez como em C++, por exemplo. 
 
Exemplos Conflitantes 
 
n1 < n2 ? printf("sim\n") : printf("nao\n"; 
 
if (n1 < n2) 
 printf("sim") 
else 
 printf("nao") 
 
O uso do operador ternário prioriza a redigibilidade em detrimento da legibilidade. Já no 
caso do if then else, a legibilidade é priorizada em detrimento da redigibilidade. 
 
2. Identifique problemas de confiabilidade e eficiência nas LPs que conhece. Verifique 
se existem casos nos quais essas propriedades são conflitantes. 
 
Problemas de de Confiabilidade 
 
C: O uso de ponteiros permite acessar áreas de memórias não alocadas, ou seja, um 
programador inexperiente poderá ocasionar erros na sua máquina. 
 
Problemas de Eficiência 
 
JAVA: O Mecanismo de tratamento de exceções faz com que haja verificações de acesso a 
posições válidas em vetores em tempo de execução, assim reduzindo a eficiência. 
 
Exemplos Conflitantes 
 
Em JAVA existe a necessidade de se fazer um teste antes de qualquer acesso aos vetores. 
Em contrapartida, a linguagem C não faz esse tipo de exigência, logo, haverá um teste a 
menos nessa linguagem, portanto o código gerado será mais veloz. Nesse aspecto, JAVA 
prioriza a Confiabilidade em detrimento da Eficiência, no caso de C, a prioridade é na 
Eficiência em relação à Confiabilidade. 
 
3. Identifique problemas de falta de ortogonalidade nas LPs que conhece. Esses 
problemas comprometem a facilidade de aprendizado na LP? 
 
JAVA: Os tipos de dados int e byte são do tipo inteiros, entretanto, a soma de um tipo byte e 
de um tipo int são feitas de formas diferentes. Isso não é intuitivo, logo, acaba por prejudicar 
o aprendizado do programador, pois ele só saberá que a combinação desses comandos 
não funcionará após o teste do mesmo. 
 
4. Reusabilidade e modificabilidade muitas vezes contribuem para a melhoria uma da 
outra. Dê exemplos de situações nas quais isso ocorre. 
 
O número PI (π) é um número irracional que por muitas vezes são utilizadas as 
aproximações de 3,14 ou 3,1415. Em C, por exemplo, caso você queira que a variável pi 
fique com um valor inalterado durante todo o algoritmo, basta que você utilize o comando 
const, por exemplo: 
 
const pi = 3,14; 
 
Isso é um exemplo de reusabilidade e modificabilidade ao mesmo tempo. Reusabilidade 
porque você poderá utilizar essa variável em diversos trechos do programa e 
Modificabilidade, pois caso você deseje que irá utilizar o valor de pi com quatro casas 
decimais, você fará a alteração apenas naquela linha de código, não prejudicando outras 
partes do algoritmo na qual aquela variável foi utilizada. 
 
 
Outro exemplo de Reusabilidade e Modificabilidade é em relação às funções. Você poderá 
importá-las em outros programas ou reutilizá-las em diversos trechos do mesmo programa. 
E caso seja necessário outras implementações, você fará apenas naquele trecho de código. 
 
 
5. Identifique situações nas quais a busca por eficiência computacional compromete 
a portabilidade de LPs e vice-versa. 
 
Quando o programador opta por uma linguagem compilada, o ganho de eficiência é 
alcançado, já que os erros já foram verificados. Porém, o código gerado após uma 
compilação não pode ser executado em diferentes arquiteturas. Já o oposto acontece 
quando se escolhe uma linguagem interpretada. A eficiência é sacrificada, visto que a 
verificação e tradução do código é feita em tempo de execução, mas a portabilidade é 
mantida. O interpretador traduz para a arquitetura em que o programa está sendo 
executado. 
 
 
6. Uma LP sempre pode ser implementada usando tanto o método de compilação 
quanto o de interpretação? Em caso positivo, discuta se existem LPs que se ajustam 
melhor a um método de implementação do que a outro. Em caso negativo, apresente 
um exemplo de uma LP na qual só se pode utilizar um método de implementação e 
justifique. 
 
Sim, Compilação e Interpretação possuem a mesma finalidade que é a tradução do código 
fonte (linguagem de programação) para linguagem de máquina. Existe algumas diferenças 
entre elas, tais como eficiência e flexibilidade. Uma delas é que enquanto na Compilação o 
código só será executado após que toda a tradução seja feita. Na Interpretação na medida 
em que cada instrução (linha de código) for traduzida ela irá sendo executada, ou seja, 
pode ser que ocorra um erro no seu código apenas no final do mesmo, mas o resto será 
executado normalmente. 
 
Existem linguagens de programação que se ajustam melhor a um método do que outro. 
 
7. Faça uma análise léxica, sintática e semântica das seguintes linhas de código C e 
descreva quais as conclusões obtidas: 
 
int a, i; 
int b = 2, c = 3; 
a = (b + c) * 2; 
i = 1 && 2 + 3 | 4; 
 
Análise léxica: 
int :: tipo de dado; 
a, i, b, c :: identificadores; 
1, 2, 3, 4 :: números; 
“=”, “,”, “;”, “&&”, “|“, “(“, “)”, “+”, “*” :: símbolos. 
 
 
 
 
 
8. Enumere e explique quais os principais fatores que influenciaram a evolução das 
LPs imperativas. 
 
- Arquitetura de Computadores: A forma de implementação dos computadores 
influencia o uso de variáveis como representação de células de memória e no uso 
de comandos como instruções. 
- Produtividade de Programação: Na medida que os softwares cresciam, a 
produtividade dos programadores tornou-se também um ponto a ser evoluído. Com 
isso, houve a incorporação de conceitos de programação estruturada, abstração de 
dados e orientação a objetos nas linguagens imperativas. 
- Eficiência de uso: Para que os recursos fossem melhores utilizados pelos usuários, 
foram incorporados conceitos de programação concorrente nas linguagens. 
 
9. Induzir a legibilidade, confiabilidade e reuso de programas são algumas da 
propriedades desejáveis em Linguagens de Programação. Mostre, através de 
exemplos (um para cada propriedade) retirados de linguagens de programação 
conhecidas, como elas podem cumprir esses papéis e justifique os seus exemplos. 
 
 
Legibilidade: 
Em Python, diferentemente de C, caracteres especiais como & e | não possuem significado 
especial. São usados os comandos and e or (uma forma muito mais intuitiva). 
 
Confiabilidade: 
A declaração de variáveis em C permite ao programador a facilitação em encontrar erros, 
pois caso seja utilizada uma variável que não foi declarada o compilador irá identificar o 
erro. 
 
Reuso: 
Subprogramas facilitam a reusabilidade. A função print de Python é um subprograma 
extremamente reutilizável. 
 
Capítulo 2 - Amarrações 
 
1. Liste pelo menos cinco diferentes tipos de amarrações que ocorrem no seguinte 
trecho de código C. 
 
float j = 3.2; 
j = j - 1.7; 
 
- A escolha do sinal "=" para denotar atribuição (tempo de projeto de linguagem) 
- A escolha do sinal "-" para denotar subtração (tempo de projeto de linguagem) 
- A associação de j ao tipo float (tempo de compilação) 
- A atribuição de 3.2 a variável j (tempo de execução) 
- A atribuição do resultado da expressão j - 1.7 a j (tempo de execução) 
 
 
2. Especifique as regras de formação de identificadores de C, C++ e JAVA. Responda 
ainda se existem limites no número máximo de caracteres que podem ser usados e 
quais tipos de identificadores especiais são considerados. 
 
C, C++ e JAVA: São Case Sensitive 
C, C++ e JAVA: O primeiro caractere deve ser letra ou sublinhado (no caso de JAVA;acrescenta-se o "ou cifrão") 
C, C++ e JAVA: Os demais caracteres podem ser letras ou dígitos ou sublinhado (no caso 
de JAVA; acrescenta-se o "ou cifrão") 
C, C++ e JAVA: Podem ter qualquer número de caracteres (C: mas apenas os 31 primeiros 
são significativos, C++: todos significativos, JAVA: sem acréscimo) 
C, C++ e JAVA: C e C++ possuem vocábulos reservados (int, char, while) e vocábulos pré-
definidos (C: printf, fopen, fclose; C++: new, delete). Java possui vocábulos reservados 
(true, boolean, try) e não possui vocábulos pré-definidos. 
 
 
3. Considere o seguinte trecho de código em ADA (QUESTÃO IMPOSSÍVEL) 
 
procedure A is 
 u : integer; 
 procedure B is 
 v : integer; 
 procedure C is 
 x : integer; 
 procedure D is 
 u : 
integer; 
 begin 
 
 null; 
 end D; 
 procedure E is 
 v : 
integer; 
 begin 
 u := 
7; 
 end E; 
 begin 
 null; 
 end C; 
 procedure F is 
 y : integer; 
 procedure G is 
 x : 
integer; 
 begin 
 
 null; 
 end G; 
 begin 
 u := 10; 
 end F; 
 begin 
 null; 
 end B; 
 begin 
 null; 
end A; 
 
Identifique quais variáveis e subprogramas são visíveis em cada um dos 
subprogramas deste trecho de código. Suponha que novos requisitos do problema 
demandam que a variável u de D possa ser acessada por G. Quais modificações 
necessitariam ser feitas no programa? Cite erros que poderiam ocorrer em situações 
como essa. 
Variáveis: 
A: u(A) 
B: u(A) e v(B) 
C: u(A), v(B) e x(C) 
D: u(A), v(B), x(C) e u(D) (u(A) acessado através de referência seletiva A.u) 
E: u(A), v(B), x(C) e v(E) (v(B) acessado através de referência seletiva B.v) 
F: u(A), v(B) e y(F) 
G: u(A), v(B), y(F) e x(G) 
Subprogramas: 
A: B 
B: A, B, C e F 
C: A, B, C, D, E e F 
D: A, B, C, D, E e F 
E: A, B, C, D, E e F 
F: A, B, C, F e G 
G: A, B, C, F e G 
Para referenciar a variável u do subprograma D em G seria necessário definí-la em B. 
A variável u de D também passaria a ser visível pelos subprogramas B, C, E e F, o que 
pode ser indesejado. Isso poderia provocar erros de alteração indevida dessa variável 
nesses subprogramas. 
 
4. Indique qual valor será escrito pelo trecho de código seguinte no caso da 
linguagem de programação utilizada adotar escopo estático e no caso dela adotar 
escopo dinâmico. 
 
procedimento sub() { 
 inteiro x = 1; 
 inteiro y = 1; 
 procedimento sub1() { 
 se (x = 1 & y = 1) então 
 sub2(); 
 senão 
 sub3(); 
 } 
 procedimento sub2() { 
 inteiro x = 2; 
 y = 0; 
 sub1(); 
 } 
 procedimento sub3() { 
 escreva( x); 
 } 
 sub1(); 
 } 
 
Cite e explique os problemas de legibilidade do trecho de código acima quando se 
adota o escopo estático e o escopo dinâmico. 
No escopo dinâmico, ao chamarmos a função sub3 depois de sub2 ser executada, a função 
fará referência ao x criado em sub2. Por isso imprimirá o valor 2. Já no escopo estático 
sub3 irá referenciar o valor de x em sub e imprimirá o valor 1. 
 
No escopo dinâmico temos que analisar a sequência em que os subprogramas são 
chamados para determinar o valor das variáveis que não são locais. É preciso mais cuidado 
e atenção por parte do programador ao manipular essas variáveis. 
 
O escopo estático é bem mais legível, pois não é necessário seguir a cadeia de chamadas 
das funções para conhecer o valor de uma variável não local, tornando o entendimento do 
código menos confuso. 
 
 
5. Compare, em termos de legibilidade, as opções de C e C++ relativas à localização 
das definições e declarações nos programas. 
 
Em C, definições e declarações devem ser feitas globalmente ou no início de um bloco de 
código. Em C++, elas podem ser feitas globalmente ou em qualquer ponto de um bloco de 
código. Como variáveis globais possuem a mesma regra de localização, a comparação 
realizada aqui se refere às declarações e definições não globais. Enquanto a opção de C++ 
possibilidade a colocação das definições e declarações bem próximas do local de seu uso, 
ela eventualmente pode ser mais difícil de ser encontrada, uma vez que pode estar 
localizada em qualquer ponto do bloco de código antes de seu primeiro uso. Por sua vez, a 
opção de C fixa o local onde as declarações e definições podem ser encontradas, 
facilitando a busca. Contudo, esse local pode ser bem distante do ponto de uso, o que pode 
dificultar a leitura. 
 
6. Identifique o problema que ocorre no seguinte trecho de código C. Exemplifique 
porque ele ocorre e indique como poderia ser resolvido. 
 
void circulo () { 
 #define pi 3.14159 
 float raio = 3; 
 float area = pi * raio * raio; 
 float perimento = 2 * pi * raio; 
} 
void pressao () { 
 float pi = 3.2, pf = 5.3; 
 float variacao; 
 variacao = pf - pi; 
} 
 
Quando o programa é compilado, o pré-processador encontra cada ocorrência da palavra 
pi, após o define, e a substitui por 3.14159. Isto causará erro na pressão. As palavras pi 
serão substituídas por uma constante, o que não deveria ter sido feito, pois a intenção era a 
criação de uma variável de nome pi (representando pressão interna). 
 
Para resolver este problema pode-se utilizar a definição "const" em vez de define. Uma 
definição através de const obedece as regras de escopo (a constante reconhecida do ponto 
de definição até o final do subprograma na qual foi definida). 
 
7. Indique quais valores serão escritos pelo seguinte programa em C. Explique sua 
resposta e discuta a postura da linguagem em termos de ortogonalidade e de 
potencialidade para indução de erros de programação. 
 
int i; 
main () { 
 printf("%d\n", i); 
 f(); 
} 
void f() { 
 int i; 
 printf("%d\n", i); 
} 
 
A variável i foi definida como global. Automaticamente ela será inicializada com o valor 0 
(zero). Portanto, na execução da função main, o primeiro valor a ser impresso é 0 (zero). 
Contudo, quando a função f é chamada, cria-se uma variável local i na memória. Variáveis 
locais em C não são inicializadas automaticamente. Assim, a impressão desta variável será 
o conteúdo corrente da área de memória aonde ela foi alocada. 
Isso caracteriza uma falta de ortogonalidade na linguagem, o que pode levar a erros de 
programação, visto que o programador pode achar que uma variável, seja global ou local, 
será sempre inicializada automaticamente com zero. 
 
 
8. Uma declaração de função é um segmento de código contendo apenas a sua 
assinatura (isto é, um segmento de código com o cabeçalho da função, mas sem seu 
corpo). Apresente uma situação na qual a declaração de funções é útil (ou 
necessária) em C. Justifique sua resposta explicando para que o compilador utiliza a 
declaração. 
 
Uma situação na qual a declaração de funções é necessária ocorre quando se deseja 
compilar um arquivo que utiliza funções definidas em outro arquivo já compilado ou que 
será compilado posteriormente. Nesse caso, as declarações são necessárias para que o 
compilador possa verificar se as chamadas das funções são consistentes com os tipos 
requeridos em sua assinatura. 
 
Capítulo 3 - Valores e Tipos de Dados 
 
1. Ponteiros são causadores potenciais de erros em programação. Dê exemplos, com 
trechos de código em C, de erros causados por ponteiros que provocam violação dos 
sistemas de tipos da linguagem, ocorrência de objetos pendentes e ocorrência de 
referências pendentes. 
 
2. Uma diferença significativa entre a definição de tipos primitivos em C++ e JAVA se 
refere ao intervalo de valores de cada tipo. Enquanto em JAVA os intervalos foram 
fixados na definição da LP, em C++ é a implementação do compilador que define 
esses intervalos. Compare estas duas abordagens, justificando a opção de cada uma 
dessas linguagens. 
A linguagem C deixa para os implementadoresdos compiladores a definição dos 
intervalos dos tipos. Essa postura diminui a portabilidade dos programas, porém 
aumenta a sua eficiência. A eficiência é maior porque permite aos implementadores 
dos compiladores selecionar os intervalos de tipos de modo a utilizar melhor os 
recursos de hardware. Já na linguagem JAVA os intervalos foram fixados na definição 
da LP pois ela prioriza a portabilidade de seus programas em detrimento da eficiência 
de execução. Isso ocorre porque a definição dos intervalos de valores dos tipos no 
projeto da linguagem implica na necessidade de emulação em software das operações 
sobre esses tipos em alguns tipos de computadores. 
 
 
3. Em geral, a verificação de uso de índice fora dos limites do vetor só pode ser 
verificado em tempo de execução. Algumas LPs, como JAVA, PASCAL e MODULA-2 
fazem a verificação dinâmica dos índices. Outras, como C, C++ e FORTRAN não 
fazem essa verificação. Justifique porque algumas LPs adotaram uma postura e 
outras adotaram uma postura oposta. Uma terceira postura, intermediária, seria gerar 
código com verificação dinâmica na fase de desenvolvimento e sem verificação 
dinâmica para a fase de uso. Discuta essa opção em termos dos conceitos usados 
para justificar as opções das LPs mencionadas acima. 
A verificação dinâmica dos índices garante que a execução do programa não 
continuará normalmente caso haja um acesso indevido, conferindo-lhe maior 
confiabilidade. Por outro lado, a necessidade de testar em tempo de execução se todo 
acesso ao vetor é apropriado implica em uma perda de desempenho na execução do 
programa. 
Logo, as LPs que optam pela verificação dinâmica dos índices de vetores em tempo de 
execução, priorizam a confiabilidade do programa em detrimento do desempenho de 
execução. As LPs que não adotam essa postura, ou seja, que não verificam os índices 
de vetores dinamicamente, priorizam o desempenho dos programas em detrimento da 
confiabilidade. 
A postura intermediária garante uma eficiência equivalente a das LPs que não fazem 
verificação dinâmica dos índices e apresentam uma maior confiabilidade do que essas 
LPs, uma vez que erros de acesso poderão ser mais facilmente identificados na fase de 
desenvolvimento. Por outro lado, a postura intermediária garante um desempenho de 
execução dos programas superior ao das LPs que verificam os índices dinamicamente, 
mas os programas se tornam menos confiáveis do que nessas LPs, uma vez que alguns 
erros de acesso podem não ser identificados na fase de desenvolvimento. 
 
4. Arrays podem ser estáticos, semi-estáticos, semi-dinâmicos e dinâmicos. 
Enquanto a criação de arrays estáticos e semi-estáticos pode ser feita facilmente em 
C, a construção de arrays semi-dinâmicos e dinâmicos envolve um maior esforço de 
programação. Responda como os mecanismos de C permitem a criação desses tipos 
de arrays. Ilustre com exemplos. 
 
5. Produtos cartesianos, uniões, mapeamentos e tipos recursivos são categorias de 
tipos compostos de dados. Ilustre, com exemplos em C, cada um desses conceitos. 
Crie ainda um novo tipo de dados que combine três desses conceitos e diga qual a 
sua cardinalidade. 
Produto cartesiano 
struct produto{ 
int codigo; 
char nome[20]; 
float valor; 
}; 
União 
union temperatura{ 
int kelvin; 
float celsius; 
}; 
Mapeamento 
int v[10]; 
Tipo recursivo 
struct lista{ 
int info; 
struct lista* prox; 
} 
Combinação 
struct lista_produto{ 
int codigo; 
char nome[20]; 
union temperatura t ; 
}; 
Cardinalidade 
#int * (#char )20 * (#float + #int) 
6. Determine a cardinalidade de cada um dos tipos abaixo, usando os conceitos de 
produto cartesiano, uniões e mapeamentos para explicar a cardinalidade dos tipos 
compostos: 
 
enum sexo {masculino, feminino}; 
enum estado_civil {solteiro, casado, divorciado}; 
enum classe {baixa, media, alta}; 
enum instrucao {primario, secundario, superior}; 
union cidadania { 
 enum classe c; 
 enum instrucao i; 
} 
struct pessoa { 
 enum sexo s; 
 enum estado_civil e; 
 union cidadania c; 
}; 
struct amostra { 
 int n; 
 struct pessoa p[10]; 
} 
 
7. Considere o seguinte programa escrito em C++: 
 
#include <iostream> 
 
int & xpto (int sinal) { 
 int p = 4; 
 if (!sinal) { 
 p* = sinal; 
 } else { 
 p++; 
} 
 return p; 
} 
 
void ypto () { 
 int c[1000]; 
 int aux; 
 for (aux = 0; aux < 1000; aux++) { 
 c[aux] = aux; 
 } 
} 
 
main () { 
 int a =; 
 int& b = xpto (a); 
 ypto(); 
 cout << b; 
} 
 
Determine quais serão as saídas possíveis do programa acima. Explique sua 
resposta. 
 
8. Considere o seguinte programa escrito em C: 
 
#include <stdio.h> 
 
int* calcula(int a) { 
 int p; 
 p = a; 
 if (a) { 
 p* = 3; 
 } else { 
 p++; 
 }; 
 return &p; 
} 
 
main() { 
 int x = 1; 
 int* b = calcula(x); 
 int* c = calcula(0); 
 printf("%d\n", *b); 
} 
 
Descreva o que ocorre nesse programa. Justifique sua resposta. 
 
9. Listas heterogêneas são estruturas de dados capazes de armazenar no seu campo 
de informação valores de tipos distintos. Uma forma de implementar listas 
heterogêneas em C é através do uso de uniões. Outra forma é através do uso de 
ponteiros para void. Mostre, através de exemplos de código em C, como se pode 
fazer para definir listas heterogêneas usando essas duas abordagens (não é preciso 
implementar as operações de lista, apenas a definição da estrutura de dados). 
Compare e discuta essas soluções em termos de redigibilidade (das operações da 
lista) e flexibilidade (em termos de necessidade de recompilação do módulo lista 
quando for necessário alterar ou incluir um novo tipo de dado no campo informação). 
 
10. Em C é possível criar estruturas de dados heterogêneas, isto é, com elementos de 
tipos diferentes. Contudo, ao se retirar um elemento da estrutura é necessário 
identificar quais operações são válidas sobre o elemento sendo removido de modo a 
evitar erros no sistema de tipos da LP. De quais maneiras isso pode ser feito? 
Compare as soluções propostas em termos de redigibilidade e em termos da 
necessidade de alteração do código usuário quando da alteração ou inclusão de um 
novo tipo de elemento na lista. 
 
11. Caracterize a diferença entre uniões livres e uniões disjuntas em termos de 
cardinalidade e segurança quanto ao sistema de tipos da linguagem. Discuta e 
exemplifique como as uniões de C podem ser utilizadas para criar estrutura de dados 
heterogêneas (isto é, que abrigam tipos de informação distintos), destacando como o 
programador (ou a linguagem, se for o caso) deve proceder para garantir o uso desse 
tipo de dado sem nem que haja violações do sistema de tipos. Discuta ainda quão 
genérica pode ser uma estrutura de dados heterogênea que se baseia no mecanismo 
de uniões. 
 
12. Muito embora JAVA seja fortemente influenciada por C, os projetistas dessa LP 
resolveram incluir o tipo boolean, o qual não existe em C. Explique porque essa 
decisão foi tomada. Dê exemplo de situação na qual a postura de C traz alguma 
vantagem. Faça o mesmo em relação a postura de JAVA. Justifique suas respostas. 
 
Capítulo 4 - Variáveis e Constantes 
 
1. Sinonímia ocorre quando uma mesma variável ou constante pode ser referenciada 
por mais de um nome em um mesmo ambiente de amarração. Mostre exemplos de 
situações nas quais isso pode ocorrer em C e JAVA. 
 
Em C: int r = 0; 
int &s = r; 
s = 10; 
2. Mostre situações nas quais a permissão de acesso ao endereço de variáveis pode 
ser benéfica ao programador. Mostre também quando isso pode ser prejudicial a 
confiabilidade dos programas. 
 
3. Edite o programa seguinte, compile-o e o execute. Relate o que ocorreu na 
compilação e durante a execução. 
 
main () { 
 char * z = "bola"; 
 *z = 'c'; 
 printf("%s\n", z); 
 printf("bola"); 
} 
 
4. Faça um programa com as linhas de código do exemplo 4.8, retirando oscomentários das linhas de código comentadas. Compile o programa usando seu 
compilador C e seu compilador C++. Relate o que aconteceu. 
 
5. Explique as vantagens de se utilizar um modelo de gerenciamento de memória 
principal com regiões de pilha e monte em relação aos modelos que só utilizam a 
pilha ou só utilizam o monte ou que alocam variáveis apenas em tempo de carga do 
programa. 
 
As vantagens de se utilizar gerenciamento de memória principal com regiões de pilha 
e monte decorrem do fato de se poder beneficiar das melhores características de cada 
um desses modelos. A pilha tem por característica principal a alocação de espaço 
suficiente para armazenar as variáveis locais de um bloco ou subprograma quando 
estes são executados. No momento que o bloco ou subprograma é encerrado, essas 
variáveis são retiradas da pilha, liberando este espaço de memória. Já o monte resolve 
o problema do aumento dinâmico das variáveis, ou seja, caso haja necessidade de 
aumentar o espaço para uma variável já existente, esse espaço adicional será reservado 
no monte, mais especificamente em local onde exista espaço contíguo suficiente para 
alocar a nova variável. 
O problema de só utilizar um dos tipos (pilha ou monte) é que sozinhos eles não são 
muito eficientes. Ao usar apenas a pilha, teríamos problemas com variáveis nas quais 
o tamanho se modifica em tempo de execução. Em relação ao uso exclusivo do monte, 
a alocação não seria muito eficiente visto que a alocação dinâmica de memória no 
monte demanda o uso de estruturas de dados para gerenciamento da memória do 
programa, e por conseguinte a sua atualização a cada momento de alocação e 
desalocação de variáveis. 
Outra possibilidade seria alocar todas as variáveis em tempo de carga. Isso se torna 
ineficaz uma vez que frequentemente haverá desperdício ou insuficiência de memória. 
Além disso, essa abordagem impede a implementação de programas recursivos, pois 
só se sabe quantas vezes o mesmo será chamado durante cada execução do programa. 
 
6. Enquanto implementações de linguagens de programação que incluem o conceito 
de ponteiros (por exemplo, C e C++) tipicamente parte da alocação e desalocação de 
memória sob a responsabilidade do programador, implementações de linguagens que 
não possuem ponteiros (por exemplo, JAVA) devem necessariamente incluir um 
sistema de gerenciamento de memória que controle e libere o espaço de memória 
utilizado. Compare estas diferentes abordagens em termos de eficiência, 
redigibilidade e confiabilidade. 
 
Eficiência 
As LPs que incluem ponteiros (e, consequentemente parte da alocação e desalocação 
de memória para o programa) são melhores que as que não possuem ponteiros. A 
explicação é que, como o programador assume a tarefa de alocação e desalocação, este 
pode fazê-lo nos momentos mais oportunos, nos exatos pontos em que as áreas de 
memória alocadas deixam de ser necessárias, e também possibilita ao programador 
desalocar a memória em pontos do programa que não interfiram no seu desempenho, 
problemas estes que podem ocorrer com o sistema de coletores de lixo. 
 
Redigibilidade 
A opção de não se utilizar ponteiros (como JAVA) deixa a programação mais fácil 
pois o programador não precisa se preocupar com os detalhes da programação com 
ponteiros. Mais especificamente, não é necessário qualquer esforço para desalocar 
memória alocada dinamicamente. Isso é executado automaticamente sem a 
interferência do programador, poupando-o de se preocupar com esses detalhes. 
 
Confiabilidade 
A programação com ponteiros é necessariamente menos confiável pois, como foi dito 
antes, a redigibilidade se reduz, o que aumenta a possibilidade de provocar erros por 
parte do programador, o qual tem de cuidar de detalhes que a programação com 
ponteiros exige. Um importante aspecto é que, na programação com ponteiros, o 
programador detém a tarefa de efetuar a desalocação dos espaços de memória 
dinâmicos, o que faz com que diversos erros possam ocorrer, tais como: esquecer de 
desalocar memória desnecessária, manutenção de referências para áreas já 
desalocadas, desalocação de áreas de memória ainda úteis. Todos esses erros não 
ocorrem com o coletor de lixo que atua nas LPs sem ponteiros pois estes processos 
são realizados sem a interferência do programador. 
 
7. Identifique inicialmente a quais subprogramas pertencem as variáveis 
referenciadas nas linhas de código do programa do exemplo 4.9. Verifique se sua 
avaliação está correta seguindo a cadeia de links estáticas na figura 4.6. 
 
8. Desenhe o estado da pilha de registros de ativação após cada chamada e 
encerramento de subprograma ao longo da execução do programa do exemplo 4.9. 
 
9. Desenhe a pilha de registros de ativação, incluindo o endereço de retorno e as 
cadeias estática e dinâmica, quando a execução atinge o ponto marcado com # no 
seguinte esqueleto de programa ADA 
 
procedure Main is 
 x: integer; 
 procedure A; 
 y: integer; 
 procedure B (k: boolean); 
 w: integer; 
 begin -- B 
 if k then 
 B (false); 
 else -- #; 
 end B; 
 procedure C; 
 z: integer; 
 begin -- C 
 ... B (true); 
 end C; 
 begin -- A 
 ... C; ... 
 end A; 
 begin -- Main 
 ... A; 
 end Main; 
 
10. Em JAVA todos os objetos (variáveis compostas) são alocados no monte. 
Explique por que isso não é tão ineficiente em relação a LPs que alocam essas 
variáveis na pilha. 
 
11. Explique como a persistência de dados é implementada em C. Compare essa 
abordagem com a de JAVA em termos de redigibilidade e legibilidade. Justifique sua 
resposta enfocando especialmente a implementação de persistência em estrutura de 
dados que utilizam ponteiros. Na sua opinião haveria algum efeito adverso em deixar 
sob o controle da linguagem de programação todo o processo de persistência de 
dados? 
 
12. Considere um programa que armazena em um grafo (usando encadeamento 
dinâmico) as distâncias terrestres entre grandes cidades brasileiras e grava essa 
estrutura em memória secundária para recuperá-la posteriormente em uma outra 
variável. Compare como seriam os códigos das implementações em C e JAVA desse 
programa em termos de redigibilidade, legibilidade e confiabilidade. 
 
 
 
Capítulo 5 - Expressões e Comandos 
 
1. Um programa deve ler uma sequência de números inteiros e imprimí-los. O 
programa deve ser interrompido quando o número lido for zero. Implemente três 
versões desse programa em C usando respectivamente os comandos iterativos com 
pré-teste, com pós-teste e um comando de escape. Discuta as soluções apresentadas 
em termos de redigibilidade e eficiência, indicando a melhor solução apresentada. 
 
 
 
2. Descreva o que ocorre em cada trecho que culmina com impressões no seguinte 
programa em C, justificando suas afirmações. 
 
#include <stdio.h> 
 
main () { 
 int a, b, c; 
 b = c = 10; 
 a = b++ + b++; 
 printf("%d\n", a); 
 printf("%dn", b); 
 a = ++c + ++c; 
 printf("%d\n", a); 
 printf("%d\n", c); 
 b = 10; 
 a = b++ +b; 
 printf("%d\n", a); 
 printf("%d\n", b); 
 a = 10; 
 b = 5; 
 if (a > b || ++b > 5) 
 printf("%d\n", b); 
 a = 1; 
 b = 5; 
 if (a > b || ++b > 5) 
 printf("%d\n", b); 
} 
 
Esse programa em C é portável? O que ocorreria se um programa equivalente (isto é, 
usando classe e com o comando apropriado de saída) fosse implementado em JAVA? 
Justifique todas as suas afirmações. 
 
 
 
3. Faça um programa em C (sem usar os escapes return ou exit) para ler um número 
inteiro positivo e calcular a tabuada de multiplicação de 0 a 9 de todos os números 
positivos inferiores ao número lido. Sempre que o resultado de uma multiplicação for 
múltiplo de dez, o programa deve perguntar ao usuário se ele deseja continuar com o 
cálculo da tabuada. Portanto, o programa deve se encerrar ao final do cálculo databuada ou quando o usuário responder que não deseja continuar o cálculo. A sua 
solução é a mais eficiente para esse problema? Porque? Como a solução mais 
eficiente seria implementada em JAVA? 
 
 
 
4. Apresente um exemplo de expressão em C onde ocorre curto-circuito associado a 
efeito colateral. Analise o efeito que tal expressão pode produzir sobre a legibilidade 
de um programa. 
 
 
 
5. O comando goto é empregado para realizar desvios incondicionais no fluxo de 
controle de programas. Com o advento das técnicas de programação estruturada, 
este comando foi muito criticado e, por muitas vezes, se sugeriu que linguagens de 
programação não deveriam incluí-lo entre seus comandos. C é uma linguagem que 
adota os princípios da programação estruturada. No entanto, C manteve o comando 
goto como um comando da linguagem. Qual a razão dessa decisão? Exemplifique, 
com um trecho de programa em C, uma situação na qual pode ser útil empregar o 
comando goto. Discuta como programadores da linguagem MODULA-2 e JAVA, que 
não incluem o goto entre seus comandos, lidam com esta situação. 
 
 
 
6. Diga qual o valor das variáveis 'a' e 'n' após cada linha do seguinte trecho de 
código C. Justifique suas respostas. 
 
n = 3; 
a = -n ++; 
a = -n + 1; 
a = -n += 1; 
 
 
 
7. Modifique o seguinte trecho de código para que ele realize a semântica sugerida 
pela sua disposição textual. 
 
if (x == 7) 
 if (y == 1) 
 z = 13; 
else z = 17; 
 
 
O trecho deve ser modificado para: 
if ( x == 7 ) { 
if ( y == 11) 
z = 13; 
} 
else z = 17; 
 
 
 
8. Veja como funciona o exemplo 5.37. Execute-o passo a passo considerando que n 
tem valor 8 e os vetores 'a' e 'b' foram definidos da seguinte maneira: 
 
int[] a = {1, 3, 6, 9, 10, 12, 16, 18}; 
int[] b = {2, 4, 5, 7, 8, 10, 11, 15}; 
 
Reimplemente esse exemplo em C garantindo que ele funcione exatamente como em 
JAVA. 
 
 
 
9. Implemente e teste o seguinte programa em C e descreva o que acontece. 
Justifique porque isso ocorre dessa maneira (isto é, apresente o racional da decisão 
tomada pelos projetistas ou implementadores dessa LP). 
 
void f() { 
 int i = 10; 
 entra; 
 i++; 
} 
 
main () { 
 f(); 
 goto entra; 
} 
 
 
 
10. Analise o seguinte programa em C, identificando o que ele faz. Faça uma crítica ao 
estilo de programação utilizado. 
 
main () { 
 int i, j, k; 
 k = 1; 
 for (i = 0; i < 10; i++) { 
 entra; 
 j = 2 * i + 1; 
 printf("i: %d, j: %d\n", i, j); 
} 
 
if (k) { 
 k = 0; 
 i = 7; 
 goto entra; 
 } 
} 
 
 
11. Algumas LPs (tal como, C) consideram a operação de atribuição como sendo uma 
espécie de expressão (isto é, a atribuição é uma operação que retorna um valor). Dê 
exemplos de situações nas quais isso pode ser vantajoso. Diga também quando essa 
característica pode ser danosa para a qualidade da programação. Justifique sua 
resposta.

Continue navegando